2012-02-25 53 views
1

我實現面搜索功能,用戶可以過濾和向下鑽取我的模型的4屬性:CityTypePurposeValue與ASP.NET MVC的自定義路線面搜索[從查詢字符串到路線]

我有這樣的刻面的視圖部分:

enter image description here

上述圖像中所顯示的每一行是可點擊的,使得用戶可以向下並執行濾波...

我做它的方式是與我通過使用自定義ActionLink輔助方法,查詢字符串:

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

這個自定義幫助程序保留以前的過濾器(查詢字符串參數)並將它們與其他操作鏈接中存在的新路由值合併。我得到的結果是這樣,當用戶已申請3個過濾器:

http://leniel-pc:8083/realty/filter?facet1=City&value1=Volta%20Redonda& 
facet2=Type&value2=6&facet3=Purpose&value3=3 

它的工作,但我想知道這樣做使用路由的更好/更清潔的方式。參數的順序可以根據用戶應用的過濾器而改變。我有這樣的想法:

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 

這可能嗎?有任何想法嗎?

回答

5

這可能嗎?有任何想法嗎?

我會繼續查詢字符串參數進行過濾。

但是,如果你想實現你已經在你的問題問的URL我將介紹兩種可能的技術。

爲此,我將在這裏介紹兩種方法我假設你已經有一個視圖模型:

public class FilterViewModel 
{ 
    public string Key { get; set; } 
    public string Value { get; set; } 
} 

和控制器:

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

第一個選項是寫

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; 
    } 
} 
:將與 IEnumerable<FilterViewModel>類型相關聯的自定義模型綁定

將在Application_Start註冊:

ModelBinders.Binders.Add(typeof(IEnumerable<FilterViewModel>), new FilterViewModelBinder()); 

,你也將有一個過濾路由器:

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

第二種可能性是寫一個自定義路由

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

這將在您的012登記方法:

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

哇!神奇的我的朋友......永遠出色的答案。我認爲現在我會繼續使用QueryString方法,因爲它使用我在問題中提到的QueryString操作按預期工作。我相信你的答案將來會用到。對我們簡單的凡人來說很有參考價值 – 2012-02-26 15:29:15

1

在我看來(這是相當主觀的),你最初的做法似乎罰款。我認爲搜索標準屬於查詢字符串,因爲它們表示您嘗試檢索的資源的子集。

您的網址不從一個邏輯資源層次結構點太大的意義。

我可能會重命名「過濾器」方法「搜索」,然而,與過濾器作爲查詢字符串變量。此外,是否有必要在查詢字符串中定義構面 - 您是否可以通過命名構面明確性來達到相同的結果,如?city = Volta & type = 6 & purpose = 3?

+0

是Mike。我非常專注於這一點,我完全忘記了我可以簡單地通過簡單的參數。不需要facet1/value1等...我已經重構了那個。感謝您添加您的答案。它有很大的幫助,有另一種觀點。 – 2012-02-25 17:27:21