Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ASP.NET MVC - Create action link preserve query string

I am currently writing my own paged list for ASP.NET Core MVC.

I struggle while creating the following:

I want to create a UrlHelper extension method: Url.PageLink(int page, int pageSize)

Within that extension method I want to return a link which reuses ALL current values for controller, action, querystring and in addition it should add/update the page, pageSize values in the querystring as well.

Questions: From where do I get the current controller and action in the UrlHelper object? What is the best way to rebuild the querystring? I can see it here url.ActionContext.HttpContext.Request.QueryString... but do I really have to manually rebuild it? Or does something like AddQueryStringValue(int key, object value) exist?

Thanks so much in advance!!! Simon

like image 336
Simon Avatar asked Feb 03 '17 10:02

Simon


2 Answers

Improvement of Simon's answer: It can be called as @Url.Current(new {page=42, id=5, foo=bar}) It will preserve query string and update/add provided values.

public static class UrlHelperExtensions
    {
        /// <summary>
        /// Get current URL with substituted values while preserving query string
        /// </summary>
        /// <param name="helper"></param>
        /// <param name="substitutes">Query string parameters or route data paremers. E.g. new { action="Index", sort = "asc"}</param>
        /// <returns></returns>
        public static string Current(this IUrlHelper helper, object substitutes)
        {
            RouteValueDictionary routeData = new RouteValueDictionary(helper.ActionContext.RouteData.Values);
            IQueryCollection queryString = helper.ActionContext.HttpContext.Request.Query;

            //add query string parameters to the route data
            foreach (var param in queryString)
            {
                if (!string.IsNullOrEmpty(queryString[param.Key]))
                {
                    //rd[param.Key] = qs[param.Value]; // does not assign the values!
                    routeData.Add(param.Key, param.Value);
                }
            }

            // override parameters we're changing in the route data
            //The unmatched parameters will be added as query string.
            foreach (PropertyDescriptor property in TypeDescriptor.GetProperties(substitutes.GetType()))
            {
                var value = property.GetValue(substitutes);
                if (string.IsNullOrEmpty(value.ToString()))
                {
                    routeData.Remove(property.Name);
                }
                else
                {
                    routeData[property.Name] = value;
                }
            }

            string url = helper.RouteUrl(routeData);
            return url;
        }
    }
like image 101
shturm Avatar answered Sep 28 '22 05:09

shturm


The question asks for Asp.Net Core. I was trying to use shturm's answer on MVC 5 and could not get it to work. I took his same concepts and changed it to work with MVC 5. If anyone needs this verison, I'm posting it here. I also added the ability to change the action and controller.

    /// <summary>
    /// Get URL with substituted values while preserving query string.
    /// </summary>
    /// <param name="helper">The url helper object we are extending.</param>
    /// <param name="action">The action we want to direct to.</param>
    /// <param name="controller">The controller we want to direct to.</param>
    /// <param name="substitutes">Query string parameters or route data paremers. E.g. new { action="Index", sort = "asc"}</param>
    /// <returns>The route string.</returns>
    public static String ActionWithOriginalQueryString(this UrlHelper helper, String action, String controller, object substitutes)
    {            
        RouteValueDictionary routeData = new RouteValueDictionary(helper.RequestContext.RouteData.Values);
        NameValueCollection queryString = helper.RequestContext.HttpContext.Request.QueryString;

        //add query string parameters to the route data
        foreach (var param in queryString.AllKeys)
        {
            if (!string.IsNullOrEmpty(queryString[param]))
            {
                //rd[param.Key] = qs[param.Value]; // does not assign the values!
                routeData.Add(param, queryString[param]);
            }
        }

        // override parameters we're changing in the route data
        //The unmatched parameters will be added as query string.
        foreach (PropertyDescriptor property in TypeDescriptor.GetProperties(substitutes.GetType()))
        {
            var value = property.GetValue(substitutes);
            if (string.IsNullOrEmpty(value?.ToString()))
            {
                routeData.Remove(property.Name);
            }
            else
            {
                routeData[property.Name] = value;
            }
        }

        //Set the controller and the action.
        routeData["controller"] = controller;
        routeData["action"] = action;

        //Return the route.
        return helper.RouteUrl(routeData);
    }
like image 39
SolidSnake4444 Avatar answered Sep 28 '22 04:09

SolidSnake4444