根据当前URL生成URL并维护QueryString

时间:2012-01-19 01:11:02

标签: c# asp.net-mvc pagination

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

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

这导致paginator显示我正在查看的Action和View的页面URL。

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

而不是/ Search?s = bla& page = 3我最终使用/ Search?page = 3

如何使用现有查询字符串生成网址?

编辑:

这是我的代码

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

2 个答案:

答案 0 :(得分:3)

使用自定义路由,您可以保留查询字符串,因为大多数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" })      
    }); 

答案 1 :(得分:0)

我是这样做的:

我已经实现了一些扩展方法,将查询字符串转换为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"))