Возможно ли это? Есть идеи?
Я бы оставил параметры строки запроса для фильтрации.
Но если вы хотите получить 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;
}
}
который будет зарегистрирован в 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;
}
}
, который будет зарегистрирован в вашем 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 }
);
}