2012-02-25 1 views
1

[QueryString을에서 경로에] 측면 검색에 나는 사용자가 필터링하고 내 모델의 4 특성에 드릴 다운 할 수있는 측면 검색 기능을 구현하고있다.사용자 정의 노선

나는이 같은 측면과 함께보기 섹션이 있습니다

enter image description here

사용자가 드릴 다운 및 필터링을 수행 할 수 있도록 위의 이미지에 표시되는 각 행이 클릭 할 ...

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

:

내가하고 있어요 방법은 내가 정의 ActionLink 도우미 메서드를 사용하여 통과 쿼리 문자열 함께 이 사용자 지정 도우미는 이전 필터 (쿼리 문자열 매개 변수)를 유지하고 다른 동작 링크에있는 새 경로 값과 병합합니다. 나는 사용자가 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을 얻으려면 2 가지 가능한 기술을 다룰 것입니다.

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

첫 번째 옵션은을 작성하는 것입니다 내가 여기에 선물 할 것이다 두 가지 접근 방식에 대한

나는 당신이 이미 뷰 모델을 가지고 있다고 가정 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; 
    } 
} 
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; 
    } 
} 
를 작성하는 것입니다을 Application_Start에 등록됩니다

012에 등록 될 방법 :

+0

와우! 환상적인 내 친구 ... 항상 뛰어난 대답. 나는 그것이 질문에서 언급 한 QueryString 조작을 사용하여 예상대로 작동하기 때문에 지금은 QueryString 접근 방식을 유지할 것이라고 생각한다. 귀하의 답변은 앞으로 사용 될 것이라고 확신합니다. 우리에게 단순한 필사자들을위한 위대한 참고서 ... –

1

내 의견으로는 (그리고 이것은 꽤 주관적입니다.) 초기 접근법은 괜찮습니다. 검색 기준은 검색하려는 리소스의 하위 집합을 나타내는 쿼리 문자열에 속한다고 생각합니다.

귀하의 URL은 논리적 인 자원 계층의 관점에서별로 의미가 없습니다.

그러나 필터 문자열을 쿼리 문자열 변수로 사용하여 "필터"메서드 "검색"의 이름을 바꾸는 것이 좋습니다. 또한 querystring에서 패싯을 정의 할 필요가 있습니까? 예를 들어? city = Volta & type = 6 & 목적 = 3과 같이 패싯의 명시적인 이름을 지정하여 동일한 결과를 얻을 수 없습니까?

+0

예 마이크. 나는 이것에 너무 집중하여 간단하게 매개 변수를 전달할 수 있다는 것을 완전히 잊었다. facet1/value1 등등 필요가 없습니다 ... 저는 이미 그것을 리팩터링했습니다. 답변을 추가해 주셔서 감사합니다. 그것은 다른 관점을 갖는데 많은 도움이됩니다. –