【问题标题】:ASP.NET MVC - Create action link preserve query stringASP.NET MVC - 创建操作链接保留查询字符串
【发布时间】:2017-06-20 17:03:14
【问题描述】:

我目前正在为 ASP.NET Core MVC 编写自己的分页列表。

我在创建以下内容时很挣扎:

我想创建一个 UrlHelper 扩展方法: Url.PageLink(int page, int pageSize)

在该扩展方法中,我想返回一个链接,该链接重用控制器、操作、查询字符串的所有当前值,此外它还应该在查询字符串中添加/更新页面、pageSize 值。

问题: 从哪里获取 UrlHelper 对象中的当前控制器和操作? 重建查询字符串的最佳方法是什么? 我可以在这里看到它 url.ActionContext.HttpContext.Request.QueryString... 但我真的必须手动重建它吗?还是存在 AddQueryStringValue(int key, object value) 之类的东西?

提前非常感谢!!! 西蒙

【问题讨论】:

  • 您打算从哪里使用您的 URLHelper?您需要设计一个包含所需信息的 ViewModel。你为什么使用查询字符串?
  • 我需要查询字符串,因为我想让这个方法适用于任何类型的视图。我不想使用特定的视图模型。我只想创建一个扩展方法 public static string PageLink(this IUrlHelper url, int page, int pageSize)
  • 我明白了。那么QS本身只是键值对的集合..你能把它作为你的分机中的参数吗?方法?
  • 当我可以通过 url.ActionContext.HttpContext.Request.QueryString 访问它时,为什么要将它传递给扩展方法?我的问题是一个不同的问题...如何在添加新的查询字符串值的同时保留当前的路由和查询字符串值...这仅在当前 UrlHelper 对象的帮助下...
  • 对不起..我不太明白这个问题...我不太习惯 UrlHelper..

标签: c# asp.net-mvc razor asp.net-core asp.net-core-mvc


【解决方案1】:

西蒙回答的改进: 可以叫@Url.Current(new {page=42, id=5, foo=bar}) 它将保留查询字符串并更新/添加提供的值。

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;
        }
    }

【讨论】:

    【解决方案2】:

    问题要求使用 Asp.Net Core。我试图在 MVC 5 上使用 shturm 的答案,但无法让它工作。我采用了他的相同概念并将其更改为与 MVC 5 一起使用。如果有人需要此版本,我将其发布在这里。我还添加了更改动作和控制器的功能。

        /// <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);
        }
    

    【讨论】:

      【解决方案3】:

      现在已经这样做了:

      public static class UrlHelperExtensions
      {
          public static string Page(this IUrlHelper url, int page, int pageSize)
          {
              //Reuse existing route values
              RouteValueDictionary resultRouteValues = new RouteValueDictionary(url.ActionContext.RouteData.Values);
      
              //Add existing values from query string
              foreach (var queryValue in url.ActionContext.HttpContext.Request.Query)
              {
                  if(resultRouteValues.ContainsKey(queryValue.Key))
                      continue;
      
                  resultRouteValues.Add(queryValue.Key, queryValue.Value);
              }
      
              //Set or add values for PagedList input model
              resultRouteValues[nameof(PagedListInputModel.Page)] = page;
              resultRouteValues[nameof(PagedListInputModel.PageSize)] = pageSize;
      
              return url.RouteUrl(resultRouteValues);
          }
      }
      

      并为 pagedlist 值创建了一个单独的输入模型“PagedListInputModel”......这样我可以确保我可以在所有地方重用它,而不必确保 page 和 pageSize 属性包含在所有需要具有正确名称的视图模型。

      欢迎任何反馈。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-05-01
        • 2012-03-29
        • 1970-01-01
        • 2012-03-06
        • 1970-01-01
        • 2021-05-13
        相关资源
        最近更新 更多