Enrutamiento personalizado de ASP.NET MVC para búsqueda

Aquí está mi escenario. Por ejemplo, digamos que necesito devolver una lista de autos en función de un criterio de búsqueda. Me gustaría tener una sola Vista para mostrar los resultados, ya que la salida será la misma, pero necesito varias formas de llegar allí. Por ejemplo, puedo tener un Formulario con un cuadro de texto para buscar por año. Es posible que tenga otra página separada que contenga un hipervínculo para todos los autos rojos de Toyota. ¿Cómo manejo estos escenarios múltiples en la misma Vista y Controlador? Mi dilema es que la búsqueda podría contener varias opciones … año, marca, modelo, etc. pero no sé dónde ponerlas.

¿Cuál es el mejor enfoque para esto? ¿Debo definir los parámetros en el enrutamiento o ir con cadenas de consulta, etc.?

Opción 1

Por supuesto, siempre puedes elegir la forma de / car / search /? Vendor = Toyota & color = Red & model = Corola y creo que será bueno para ti.

routes.MapRoute( "CarSearch", "car/search", new { controller = "car", action = "search" } ); 

Puede obtener parámetros de Request.Params en acción en este caso.

opcion 2

O puede definir params en la tabla de enrutamiento, pero AFAIK requerirá crear un conjunto de reglas para todas las combinaciones posibles, porque un orden de params importa, por ejemplo:

  routes.MapRoute( "CarSearch1", "car/search/vendor/{vendor}/color/{color}/model/{model}", new {controller = "car", action = "search"} ); routes.MapRoute( "CarSearch2", "car/search/color/{color}/vendor/{vendor}/model/{model}", new {controller = "car", action = "search"} ); routes.MapRoute( "CarSearch3", "car/search/model/{model}/color/{color}/vendor/{vendor}", new {controller = "car", action = "search"} ); 

… etc. Es cierto si va con el MvcRouteHandler estándar.

Pero fue un camino fácil 🙂

Opción 3

La forma difícil, pero, creo, más elegante, es hacer su propia implementación de IRouteHandler: le dará mucha más flexibilidad en el orden de parámetros. Pero, de nuevo, es una manera difícil, no te vayas si tienes una aplicación simple. Entonces, solo por ejemplo de cómo hacerlo de esta manera (ejemplo muy simple):

Agregue una nueva ruta a la lista de rutas:

 routes.Add ( new Route ( "car/search/{*data}", new RouteValueDictionary(new {controller = "car", action = "search", data = ""}), new MyRouteHandler() ) ); 

Agregue clases que modificarán la cadena de procesamiento de solicitud estándar:

 class MyRouteHandler : IRouteHandler { public IHttpHandler GetHttpHandler(RequestContext requestContext) { return new MyHttpHandler(requestContext); } } class MyHttpHandler : MvcHandler { public MyHttpHandler(RequestContext requestContext) : base(requestContext) { } protected override void ProcessRequest(HttpContextBase httpContext) { IController controller = new CarController(); (controller as Controller).ActionInvoker = new MyActionInvoker(); controller.Execute(RequestContext); } } class MyActionInvoker : ControllerActionInvoker { protected override ActionResult InvokeActionMethod(MethodInfo methodInfo, IDictionary parameters) { // if form of model/{model}/color/{color}/vendor/{vendor} var data = ControllerContext.RouteData.GetRequiredString("data"); var tokens = data.Split('/'); var searchParams = new Dictionary(); for (var i = 0; i < tokens.Length; i++) { searchParams.Add(tokens[i], tokens[++i]); } parameters["searchParams"] = searchParams; return base.InvokeActionMethod(methodInfo, parameters); } } 

En el controlador:

 public ActionResult Search(IDictionary searchParams) { ViewData.Add ( // output 'model = Corola, color = red, vendor = Toyota' "SearchParams", string.Join(", ", searchParams.Select(pair => pair.Key + " = " + pair.Value).ToArray()) ); return View(); } 

Y funcionará con cualquier orden de parámetros de búsqueda:

 /car/search/vendor/Toyota/color/red/model/Corola /car/search/color/red/model/Corola/vendor/Toyota /car/search/model/Corola/color/red/vendor/Toyota 

Pero también no te olvides de hacer una lógica de generación de enlaces, porque Html.ActionLink y Html.RenderLink no te darán url en forma bonita de / car / search / model / Corola / color / red / vendor / Toyota, por lo que necesitarás para hacer un generador de enlaces personalizado.

Entonces, si necesita un enrutamiento realmente flexible, será mejor que lo haga de esta manera 🙂

Cada método (acción) en el controlador tomaría diferentes parámetros, pero crearía la misma colección de resultados de búsqueda. Entonces, cada uno

 return View("SearchResult", searchResultCollection); 

Todos usan la misma vista, SearchResult.aspx.

Algo en esta línea debería hacer lo que está buscando. Observe cómo hay dos métodos de acción diferentes, pero ambos devuelven una llamada a DisplayResults (), por lo que terminan usando la misma vista, con diferentes ViewData.

 public class SearchController : Controller { public ActionResult ByColor(Color[] colors) { List results = carRepository.FindByColor(colors); return(DisplayResults(result)); } public ActionResult ByMake(string make) { List results = carRepository.FindByMake(make); return(DisplayResults(results)); } private ActionResult DisplayResults(IList results) { // Here we explicitly return the view /Views/Search/Results.aspx // by specifying the view name in the call to View(); return(View("Results", results)); } }