elwyn
elwyn

Reputation: 10521

ASP.NET MVC 3 Multiple routes to accommodate filtering

I'm building a search of sorts, which has various filters available.

I want to map these filter options to a nice URL - however I'm running into a problem with setting up my routes, and I feel like there must be a better way to do this.

I have the following action on my Flights controller (for the sake of an example):

public ActionResult Find(string origin, string destination, DateTime? DepartureDateTime, int? flexibleDays, int? Page, string someValue)
{
    //do fun stuff here
}

I want all of the following URLs to route to this action:

example.com/Flights/
example.com/Flights/From/London/
example.com/Flights/To/Fiji/
example.com/Flights/From/London/To/Fiji/
example.com/Flights/From/London/To/Fiji/2011-07-16/    (here I wish a default value of zero be applied to flexibleDays)
example.com/Flights/From/London/To/Fiji/2011-07-16/flexible/   (here I wish a non-zero default value to be set to the flexibleDays parameter)
example.com/Flights/From/London/To/Fiji/2011-07-16/flexible/5/    (here a value is specified for flexibleDays)

I'd like the order of the first two things to be reversible as well, e.g.:

example.com/Flights/From/London/To/Fiji/
example.com/Flights/To/Fiji/From/London/

As well as those 'base' URLs, I would like to be able to add query strings:

example.com/Flights/From/London/To/Fiji/2011-07-16/flexible/5/?Page=2&someValue=foobar

These query string parameters would be null/empty when not present.

Now that I have described what I WANT, here's my first crack at this. Basically, I just started adding different route rules for every permutation of the search.

routes.MapRoute(
            "Bad1", // Route name
            "Flights/from/{origin}/to/{destination}/{DepartureDateTime}/flexible/{flexibleDays}", // URL with parameters
            new { controller = "Flights", action = "Find", DepartureDateTime = UrlParameter.Optional, flexibleDays = UrlParameter.Optional } // Parameter defaults
        );

        routes.MapRoute(
            "Bad2", // Route name
            "Flights/to/{destination}/from/{origin}/{DepartureDateTime}/flexible/{flexibleDays}", // URL with parameters
            new { controller = "Flights", action = "Find", DepartureDateTime = UrlParameter.Optional, flexible = UrlParameter.Optional } // Parameter defaults
        );

        routes.MapRoute(
            "Bad3", // Route name
            "Flights/from/{origin}/to/{destination}/{DepartureDateTime}/", // URL with parameters
            new { controller = "Flights", action = "Find", DepartureDateTime = UrlParameter.Optional } // Parameter defaults
        );

        routes.MapRoute(
            "Bad4", // Route name
            "Flights/to/{destination}/from/{origin}/{DepartureDateTime}/", // URL with parameters
            new { controller = "Flights", action = "Find", DepartureDateTime = UrlParameter.Optional } // Parameter defaults
        );

        routes.MapRoute(
            "Bad5", // Route name
            "Flights/from/{origin}/{DepartureDateTime}/flexibe/{flexibleDays}", // URL with parameters
            new { controller = "Flights", action = "Find", DepartureDateTime = UrlParameter.Optional, flexible = UrlParameter.Optional } // Parameter defaults
        );

        routes.MapRoute(
            "Bad6", // Route name
            "Flights/to/{destination}/{DepartureDateTime}/flexible/{flexibleDays}", // URL with parameters
            new { controller = "Flights", action = "Find", DepartureDateTime = UrlParameter.Optional, flexible = UrlParameter.Optional } // Parameter defaults
        );

Now this is mostly working, but it is quickly growing out of hand. Assume that this example I have used is simplified, and there were many many more query string, for example, and a few more "URL'd parameters" like the /flexible/{flexibleDays} I have above.

Is there a better, more maintainable, more scailable solution to this? Or do I just have to very very carefully map out every single combination of URLs I want to have?

Also, I am open to suggestions about other URL structures. Although I am still interested if there is a nicer way of setting up the routes I have specified.

Upvotes: 1

Views: 3301

Answers (2)

NinjaNye
NinjaNye

Reputation: 7126

To ease your pain slightly you might want to consider creating a From and To action method. This will make your routing somewhat easier.

For reference, you might find the following link helpful. http://haacked.com/archive/2008/03/13/url-routing-debugger.aspx

Edit: Personally I'd have To and From action methods on the Flights contoller and pass the rest in as qs variables:

/Flights/From/Auckland?to=London
/Flights/To/London?from=auckland

This would mean less routing whilst keeping your urls clean (even with the additional params)

Upvotes: 0

Lukáš Novotný
Lukáš Novotný

Reputation: 9052

There is no built in way to do what you want without crating routes for all possible combinations. You can write custom route, but it won't be exactly easy. What you want is basically parsing key value pairs where both key and value can have default and values can have constraint. Also do not forget about building url from those values and back.

  • from/{string}
  • to/{string}
  • {datetime} (no key)
  • flexible/{int} (default value)

Specifying key for DepartureDateTime would simplify it little bit (=each value would have key). The url for custom route would look like "Flights/{p1}/{p2}/{p3}/{p4}/" etc. where all parameters would have default to UrlParemeter.Optional or "Flights/{*args}". Then you would do the mapping in GetRouteData and GetVirtualPath to desired route values.

Another way would be writing method that would create all combinations based on parameters, but if you want to expand those parameters it could hurt the performance eventually.

Upvotes: 2

Related Questions