2008-12-18 11 views
31

Oto mój scenariusz. Na przykład powiedzmy, że muszę zwrócić listę samochodów na podstawie kryteriów wyszukiwania. Chciałbym mieć pojedynczy widok, aby wyświetlić wyniki, ponieważ wynik będzie taki sam, ale potrzebuję kilku sposobów, aby się tam dostać. Na przykład mogę mieć formularz z polem tekstowym do wyszukiwania według roku. Mogę mieć inną oddzielną stronę zawierającą hiperłącze do wszystkich czerwonych samochodów marki Toyota. Jak obsłużyć te wiele scenariuszy w tym samym widoku i kontrolera. Mój dylemat polega na tym, że wyszukiwanie może zawierać kilka opcji ... rok, marka, model itp., Ale nie wiem, gdzie je umieścić.Niestandardowe kierowanie ASP.NET MVC do wyszukiwania

Jakie jest najlepsze podejście do tego? Czy powinienem zdefiniować parametry w routingu, czy iść z ciągami zapytań itp.?

Odpowiedz

78

Wariant 1

Oczywiście zawsze może wybrać drogę/samochód/Szukaj /? Vendor = Toyota & color = red & Model = Corola i myślę, że to będzie dobre dla ciebie .

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

Możesz otrzymać params z Request.Params w akcji w tym przypadku.

Opcja 2

Albo można zdefiniować params w tablicy routingu, ale AFAIK to będzie konieczne, aby zbiór zasad dla wszystkich możliwych kombinacji, ponieważ kolejność params względu na to, na przykład:

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

... tak dalej. To prawda, jeśli idziesz ze standardowym MvcRouteHandler.

ale to było proste sposoby :)

Wariant 3

twardego, ale, moim zdaniem, najbardziej elegancki sposób to zrobić własną implementację IRouteHandler - to daje dużo więcej elastyczność w porządku params. Ale znowu, jest to trudny sposób, nie idź z nim, jeśli masz prostą aplikację. Tak, tylko na przykład, jak zrobić to w ten sposób (bardzo prosty przykład):

Dodaj nową trasę do listy tras:

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

Dodaj klas, które będą podkręcać standardowego łańcucha przetwarzania żądania:

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<string, object> parameters) 
    { 
     // if form of model/{model}/color/{color}/vendor/{vendor} 
     var data = ControllerContext.RouteData.GetRequiredString("data"); 
     var tokens = data.Split('/'); 

     var searchParams = new Dictionary<string, string>(); 
     for (var i = 0; i < tokens.Length; i++) 
     { 
      searchParams.Add(tokens[i], tokens[++i]); 
     } 

     parameters["searchParams"] = searchParams; 

     return base.InvokeActionMethod(methodInfo, parameters); 
    } 
} 

W sterowniku:

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

I to będzie pracować z dowolnymi parametrami wyszukiwania zamówić:

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

Ale również nie zapomnij zrobić logikę generowania linków, ponieważ Html.ActionLink i Html.RenderLink nie da Ci URL w ładnej formie/samochód/search/model/Corola/color/red/vendor/Toyota, więc musisz utworzyć niestandardowy generator linków.

Tak więc, jeśli potrzebujesz naprawdę elastycznego routingu - lepiej pójdź tą drogą :)

+0

Myślę, że moim najlepszym sposobem działania w tej chwili będzie opcja 1. Opcja 2 była sposobem, w jaki byłem początkowo na czele, ale wydaje się, że nie ma potrzeby umieszczania wszystkich możliwych kombinacji tras. Opcja 3 wygląda dobrze na później, jeśli chcę refaktoryzować, ale będąc MVC NOOB, będę trzymać się łatwej trasy. –

+0

Doskonała odpowiedź! @Eric, nie zapomnij o awansie – AnthonyWJones

+0

Dziękuję, Anthony :) – maxnk

0

Każda metoda (działanie) na kontrolerze będzie miała różne parametry, ale utworzy tę samą kolekcję wyników wyszukiwania. Następnie każdy z nich będzie używał tego samego widoku, SearchResult.aspx.

0

Coś w tym stylu powinno robić to, na co masz ochotę. Zwróć uwagę, że istnieją dwie różne metody działania, ale obie zwracają wywołanie funkcji DisplayResults() - w efekcie używają tego samego widoku z różnymi danymi ViewData.

public class SearchController : Controller { 

    public ActionResult ByColor(Color[] colors) { 
     List<Car> results = carRepository.FindByColor(colors); 
     return(DisplayResults(result)); 
    } 

    public ActionResult ByMake(string make) { 
     List<Car> results = carRepository.FindByMake(make); 
     return(DisplayResults(results)); 
    } 

    private ActionResult DisplayResults(IList<Car> 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)); 
    } 
} 
+0

Dzięki. Twoim przykładem jest to, jak zaczęło się moje myślenie, ale myślę, że mój brak zrozumienia dla routingu MVC sprawił, że wpadłem w szał. Patrzyłem na to tylko przez kilka dni. W jaki sposób przekażesz tablicę kolorów do ActionResult. Rozumiem, że te parametry pochodzą z adresu URL: –