【问题标题】:Generate URL based off of the current URL and maintain QueryString根据当前 URL 生成 URL 并维护 QueryString
【发布时间】:2012-02-13 17:54:08
【问题描述】:

我有一个用于显示项目列表的局部视图,我在几个不同的地方使用这个局部视图。在这个局部视图中,我使用了分页器 -

@Html.PagedListPager(Model, page => Url.Action(null, new { page = page }))

这会导致分页器显示我正在查看的任何操作和视图的页面 url。

问题是,在我的搜索页面上,我使用查询字符串作为搜索字符串,而 Url.Action 方法不包含现有的查询字符串参数。

我最终得到的是 /Search?page=3 而不是 /Search?s=bla&page=3

如何使用现有的查询字符串生成 url?

编辑:

这是我的代码

    public static void RegisterRoutes(RouteCollection routes)
    {
        routes.IgnoreRoute("{resource}.axd/{*pathInfo}");


        routes.Add(
        "Search",
        new SearchRoute("Search", new MvcRouteHandler())
        {
            Defaults = new RouteValueDictionary(
                new { controller = "Search", action = "Index" })
        }); 


        routes.MapRoute(
            "Default",
            "{controller}/{action}/{id}",
            new { controller = "Call", action = "Index", id = UrlParameter.Optional }


        );



    }

    public class SearchRoute : Route
    {
        public SearchRoute(string url, IRouteHandler routeHandler)
            : base(url, routeHandler)
        {
        }

        public override VirtualPathData GetVirtualPath(RequestContext requestContext, RouteValueDictionary values)
        {

            System.Diagnostics.Debug.WriteLine(Url);

            if (HttpContext.Current != null)
            {

                string s = HttpContext.Current.Request.QueryString["s"];

                if (!string.IsNullOrEmpty(s))
                    values.Add("s", s);

            }

            return base.GetVirtualPath(requestContext, values);
        }
    }

【问题讨论】:

    标签: c# asp.net-mvc pagination


    【解决方案1】:

    使用自定义路由,您可以保留查询字符串,因为大多数 Url 生成逻辑使用路由来生成 URL。在这种情况下,我正在检查 Request 对象中是否有一个名为 XXX 的查询字符串,如果它存在,则将其添加到路由中,如果您愿意,可以使其更通用。

    using System.Web;
    using System.Web.Routing;
    
    public class PreserveQueryStringRoute : Route
    {
        public PreserveQueryStringRoute(string url, IRouteHandler routeHandler)
            : base(url, routeHandler)
        {
        }
    
        public override VirtualPathData GetVirtualPath(RequestContext requestContext, RouteValueDictionary values)
        {
            if(HttpContext.Current != null)
            {
                values = new RouteValueDictionary(values);   //this is the bug fix!
    
                if (!string.IsNullOrEmpty(HttpContext.Current.Request.QueryString["XXX"]))
                    values.Add("XXX", HttpContext.Current.Request.QueryString["XXX"]);
    
            }
    
            var path = base.GetVirtualPath(requestContext, values);
            return path;
        }
    }
    

    在 global.ascx 中按照正常方式注册路由(尽管可能不是像我下面这样的通用匹配)

            routes.Add(
                "Default",
                new PreserveQueryStringRoute("{controller}/{action}/{id}", new MvcRouteHandler())
                {
                    Defaults = new RouteValueDictionary(
                        new { controller = "Home", action = "Index", id = UrlParameter.Optional })
                });   
    

    编辑:

    好的,这是一个更新......它是一个错误修复,以及如何注册路由的示例(请参阅上面的更正代码以获取错误修复)

    注册方法如下:

        routes.Add(      
        "Search",      
        new SearchRoute("Search", new MvcRouteHandler())      
        {      
            Constraints = new RouteValueDictionary(      
                new { controller = "Search", action = "Index" })      
        }); 
    

    【讨论】:

    • 太棒了。你这个男人。如果其他人使用它,请记住将调用 Routes.Add 置于默认路由之上。
    • 它将查询字符串放在我的搜索页面上生成的所有网址上。可以修复吗?我只需要搜索网址上的查询字符串。
    • 事实上,我在哪里并不重要,如果我将 xxx=something 放在我的查询字符串中,它将被添加到所有生成的 url。
    • 我在上面注册路由的方式(仅作为示例)意味着它几乎可以匹配任何路由。您应该以不太通用的方式注册它,以便它只影响 url 生成特定页面
    • GetVirtualPath 应该检查 url 是否匹配。通过覆盖它,并在您检查 url 是否匹配之前向路由添加一个值,您最终会在每个 url 上添加查询字符串,无论它是否是 url 中指定的那个。我浪费了几个小时试图让您的解决方案发挥作用。
    【解决方案2】:

    我是这样做的:

    我已经实现了一些扩展方法来将查询字符串转换为RouteValueDictionary 并在其中设置单个项目:

    public static class RouteValueDictionaryExtensions
    {
        public static RouteValueDictionary ToRouteValues(this NameValueCollection queryString)
        {
            if (queryString == null || queryString.HasKeys() == false) 
                return new RouteValueDictionary();
    
            var routeValues = new RouteValueDictionary();
            foreach (string key in queryString.AllKeys)
                routeValues.Add(key, queryString[key]);
    
            return routeValues;
        }
    
        public static RouteValueDictionary Set(this RouteValueDictionary routeValues, string key, string value)
        {
            routeValues[key] = value;
            return routeValues;
        }
    
        public static RouteValueDictionary Merge(this RouteValueDictionary primary, RouteValueDictionary secondary)
        {
            if (primary == null || primary.Count == 0)
            {
                return secondary ?? new RouteValueDictionary();
            }
    
            if (secondary == null || secondary.Count == 0)
                return primary;
    
            foreach (var pair in secondary)
                primary[pair.Key] = pair.Value;
    
            return primary;
        }
    
        public static RouteValueDictionary Merge(this RouteValueDictionary primary, object secondary)
        {
            return Merge(primary, new RouteValueDictionary(secondary));
        }
    }
    

    这使得创建链接成为可能,例如:

    Url.RouteUrl(Request.QueryString.ToRouteValues().Set("Key", "Value"))
    

    或者这个:

    Url.RouteUrl(Request.QueryString.ToRouteValues().Merge(new {key = "value"}))
    

    我还可以链接这些扩展方法以实现更大的灵活性:

    Url.RouteUrl(Request.QueryString.ToRouteValues().Set("Key", "Value").Set("AnotherKey", "AnotherValue"))
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-01-01
      • 1970-01-01
      • 2013-04-08
      • 2021-05-07
      • 2014-01-04
      • 2018-11-08
      • 1970-01-01
      相关资源
      最近更新 更多