views:

83

answers:

3

Currently my URL structure is like this:

www.example.com/honda/ www.example.com/honda/add www.example.com/honda/29343

I have a controller named HondaController.

Now I want to refactor this so I can support more car manufacturers. The database has a table that stores all the manufacturers that I want to support.

How can I keep my URL like above, but now support:

www.example.com/ford www.example.com/toyota/add etc.

I can easily rename the HondaController to CarController, and just pass in the string 'honda' or 'toyota' and my controller will work (it is hard coded to 'honda' right now).

Is this possible? I'm not sure how how to make a route dynamic based on what I have in the database.

A: 

What I recommend is instead using:

domain/m/<manufacturer>/<action>

Where 'm' is the manufacturer controller. This will allow you to use the same controller for all of your extensions and save you a lot of headache in the future, especially when adding new features. Using a one-letter controller is often times desirable when you want to retain your first variable ( in this case) as the first point of interest.

Aaron
+3  A: 

Any part of your route can be dynamic just be making it into a route parameter. So instead of "/honda/{action}", do:

/{manufacturer}/{action}

This will give you a parameter called "manufacturer" that was passed to your action method. So your action method signature could now be:

public ActionResult add(string manufacturer) { }

It would be up to you to verify that the manufacturer parameter correctly matched the list of manufacturers in the database - it would probably be best to cache this list for a quicker lookup.


Updated: What I mean by "you have to take out the default parameters" for the default route is this. If you have:

route.MapRoute("Default", "/{controller}/{action}/{id}", 
                new { id = 1 }    // <-- this is the parameter default
              );

then this route will match any url with two segments, as well as any url with three segments. So "/product/add/1" will be handled by this route, but so will "/product/add". If you take out the "new { id = 1 }" part, it will only handle URL's that look like "/product/add/1".

womp
womp, but won't that conflict with the default route? routes.MapRoute( "Default", // Route name "{controller}/{action}/{id}", // URL with parameters new { action = "Index", id = ""} // Parameter defaults );
mrblah
It doesn't really conflict, but it would take precedence. Always map your most specific routes first - so map your {controller}/{action}/{id} route before /{manufacturer}/{action}/. This gives the default route a chance to match the URL first. Also note that you can always do away with the default route if you're not using it.
womp
Note you would have to take out the default parameters ;)
womp
what do you mean take the default parameters out?
mrblah
@homestead - I updated my answer to address your last comment.
womp
+1  A: 

i have made something like this for granite as i wanted to have a material controller but have a url like so:

black/granite/worktops black/quartz/worktops

etc

i did this route:

routes.MapRoute("Quote", "quote/{color}/{surface}/{type}",
                        new {controller = "Quote", action = "surface"});

swap quote for car so u can have:

car/honda/accord

your route can then be

routes.MapRoute("cars", "car/{make}/{model}",
                        new {controller = "Cars", action = "Index"});

your actionResults can then look like this:

public ActionResult Index(string make, string model)
    {
        //logic here to get where make and model

        return View();
    }

that i think covers it

minus4