使用ASP.NET MVC进行分面搜索的自定义路由[从QueryString到Route]

Len*_*rri 2 asp.net-mvc filtering routes faceted-search query-string

我实现面搜索功能,用户可以过滤和向下钻取4我的模型的属性:City,Type,PurposeValue.

我有一个像这样的facet的视图部分:

在此输入图像描述

上图中显示的每一行都是可点击的,以便用户可以向下钻取并进行过滤...

我这样做的方式是使用自定义ActionLink帮助器方法传递的查询字符串:

 @Html.ActionLinkWithQueryString(linkText, "Filter",
                                 new { facet2 = Model.Types.Key, value2 = fv.Range });
Run Code Online (Sandbox Code Playgroud)

此自定义帮助程序保留先前的筛选器(查询字符串参数),并将它们与其他操作链接中存在的新路由值合并.当用户应用了3个过滤器时,我得到了这样的结果:

http://leniel-pc:8083/realty/filter?facet1=City&value1=Volta%20Redonda&
facet2=Type&value2=6&facet3=Purpose&value3=3
Run Code Online (Sandbox Code Playgroud)

它正在工作,但我想知道使用路线更好/更清洁的方式.参数的顺序可以根据用户应用的过滤器而改变.我有这样的想法:

http://leniel-pc:8083/realty/filter // returns ALL rows

http://leniel-pc:8083/realty/filter/city/rio-de-janeiro/type/6/value/50000-100000

http://leniel-pc:8083/realty/filter/city/volta-redonda/type/6/purpose/3

http://leniel-pc:8083/realty/filter/type/7/purpose/1

http://leniel-pc:8083/realty/filter/purpose/3/type/4

http://leniel-pc:8083/realty/filter/type/8/city/carangola
Run Code Online (Sandbox Code Playgroud)

这可能吗?有任何想法吗?

Dar*_*rov 7

这可能吗?有任何想法吗?

我会保留查询字符串参数进行过滤.

但是如果你想在你的问题中找到你要求的网址,我将介绍两种可能的技巧.

对于我将在这里介绍的两种方法,我假设您已经有一个视图模型:

public class FilterViewModel
{
    public string Key { get; set; }
    public string Value { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

和一个控制器:

public class RealtyController : Controller
{
    public ActionResult Filter(IEnumerable<FilterViewModel> filters)
    {
        ... do the filtering ...
    }
}
Run Code Online (Sandbox Code Playgroud)

第一个选项是编写一个与该IEnumerable<FilterViewModel>类型相关联的自定义模型绑定器:

public class FilterViewModelBinder : IModelBinder
{
    public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
    {
        var filtersValue = bindingContext.ValueProvider.GetValue("pathInfo");
        if (filtersValue == null || string.IsNullOrEmpty(filtersValue.AttemptedValue))
        {
            return Enumerable.Empty<FilterViewModel>();
        }

        var filters = filtersValue.AttemptedValue;
        var tokens = filters.Split('/');
        if (tokens.Length % 2 != 0)
        {
            throw new Exception("Invalid filter format");
        }

        var result = new List<FilterViewModel>();
        for (int i = 0; i < tokens.Length - 1; i += 2)
        {
            var key = tokens[i];
            var value = tokens[i + 1];
            result.Add(new FilterViewModel
            {
                Key = tokens[i],
                Value = tokens[i + 1]
            });
        }

        return result;
    }
}
Run Code Online (Sandbox Code Playgroud)

将在以下地址注册Application_Start:

ModelBinders.Binders.Add(typeof(IEnumerable<FilterViewModel>), new FilterViewModelBinder());
Run Code Online (Sandbox Code Playgroud)

你还将有一个过滤路线:

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

    routes.MapRoute(
        "Filter",
        "realty/filter/{*pathInfo}",
        new { controller = "Realty", action = "Filter" }
    );

    routes.MapRoute(
        "Default",
        "{controller}/{action}/{id}",
        new { controller = "Home", action = "Index", id = UrlParameter.Optional }
    );
}
Run Code Online (Sandbox Code Playgroud)

第二种可能性是编写自定义路线

public class FilterRoute : Route
{
    public FilterRoute()
        : base(
            "realty/filter/{*pathInfo}", 
            new RouteValueDictionary(new 
            { 
                controller = "realty", action = "filter" 
            }), 
            new MvcRouteHandler()
        )
    {
    }

    public override RouteData GetRouteData(HttpContextBase httpContext)
    {
        var rd = base.GetRouteData(httpContext);
        if (rd == null)
        {
            return null;
        }

        var filters = rd.Values["pathInfo"] as string;
        if (string.IsNullOrEmpty(filters))
        {
            return rd;
        }

        var tokens = filters.Split('/');
        if (tokens.Length % 2 != 0)
        {
            throw new Exception("Invalid filter format");
        }

        var index = 0;
        for (int i = 0; i < tokens.Length - 1; i += 2)
        {
            var key = tokens[i];
            var value = tokens[i + 1];
            rd.Values[string.Format("filters[{0}].key", index)] = key;
            rd.Values[string.Format("filters[{0}].value", index)] = value;
            index++;
        }

        return rd;
    }
}
Run Code Online (Sandbox Code Playgroud)

将在您的RegisterRoutes方法中注册:

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

    routes.Add("Filter", new FilterRoute());

    routes.MapRoute(
        "Default",
        "{controller}/{action}/{id}",
        new { controller = "Home", action = "Index", id = UrlParameter.Optional }
    );
}
Run Code Online (Sandbox Code Playgroud)