Refactoring my route to be more dynamic - asp.net-mvc

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.

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".

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

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.

Related

Mvc: Same ActionResult with different name depending url

I would like to know what's the best way to achieve this.
I have an ActionResult in my controller, actually it has news name, now I need to internationlize my website and I can't have the same news name, it must to change depending the country where it's visited.
for example, now I need something like.
www.something.com/en/us/news for english version
www.something.com/co/es/noticias for spanish version
you have the point for the next countries.
I don't think I need to create x methods depending x urls that make exactly the same, but I don't know how to achieve it in a really efficient way ... thanks
You could create a new class TranslatedRoute and TranslationProvider to map the different translations to the same action. Then you can plug these into the routing system and override the default mapping.
Here's a good blog post which describes the idea: http://blog.maartenballiauw.be/post/2010/01/26/Translating-routes-%28ASPNET-MVC-and-Webforms%29.aspx
How does your routing work now? Maybe something like this answer would work, if you don't already use it. Perhaps something variation of this, with the parts of the URL in a different order, to suit your needs. For example, the controller doesn't necessarily have to come first in the route (or at all, in this case just always using the same controller name). Make some sort of map that gets you the word "news" in each different language, using the language code as a key.
// populate this map somewhere - language code to word for "news" (and any other name of the controllers that you have)
var newsControllerMap = new Dictionary<string, string>();
newsControllerMap["en"] = "news"; // etc.
// ...
// inside of the RouteConfig class (MVC 4) or RegisterRoutes() method in Global.asax.cs (MVC 3)
// just making an assumption that whatever class/entity you use ("LanguageAndCountry" in this case) also has a country code to make this easier. Obviously this would be refactored to have better naming/functionality to make sense and meet your needs.
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
LanguageAndCountryRepository langRepo = new LanguageAndCountryRepository();
var languagesandCountries = langRepo.GetAllLanguagesWithCountries();
foreach (LanguageAndCountry langAndCountry in languagesandCountries)
{
routes.MapRoute(
"LocalizationNews_" + langAndCountry.LanguageAbbreviation,
langAndCountry.LanguageAbbreviation + "/" + langAndCountry.CountryCode + "/" + newsControllerMap[langAndCountry.LanguageAbbreviation],
new { lang = language.LanguageAbbreviation, country = langAndCountry.CountryCode, controller = "News", action = "Index"});
// map more routes to each controller you have, each controller having a corresponding map to the name of the controller in any given language
}

ASP.NET MVC Dynamic Action with Hyphens

I am working on an ASP.NET MVC project. I need to be able to map a route such as this:
http://www.mysite.com/Products/Tennis-Shoes
Where the "Action" part of the URL (Tennis-Shoes") could be one of a list of possibilities. I do not want to have to create a separate Action method in my controller for each. I want to map them all to one Action method and I will handle the View that is displayed from there.
I have this working fine by adding a route mapping. However, there are some "Actions" that will need to have a hyphen in them. ASP.NET MVC routing is trying to parse that hyphen before I can send it to my action. I have tried to create my own custom Route Handler, but it's never even called. Once I had a hyphen, all routes are ignored, even my custom one.
Any suggestions? Details about the hyphen situation? Thanks you.
Looking at the URL and reading your description, Tennis-Shoes in your example doesn't sound like it should be an action, but a Route parameter. Let's say we have the following controller
public class ProductsController : Controller
{
public ActionResult Details(string product)
{
// do something interesting based on product...
return View(product);
}
}
The Details action is going to handle any URLs along the lines of
http://www.mysite.com/Products/{product}
using the following route
routes.MapRoute(
null,
"Products/{product}",
new
{
controller = "Products",
action = "Details"
});
You might decide to use a different View based on the product string, but this is just a basic example.

route to reflect hierarchical url/menu structure

i've created a basic mvc3 website whereby each controller represents the first folder in a url structure.
for example, the "food" and "drinks" folders below are controller. there are only two controllers which contain all of the sub-items in them.
ie in the first line of the example, controller=food, method=asian
in the second line controller=food, method=pad-thai and so on and so forth.
www.mysite.com/food/asian/
www.mysite.com/food/asian/pad-thai
www.mysite.com/food/italian/chicken-parmigiana
www.mysite.com/drinks/cocktails/bloody-mary
how would i write routes so that www.mysite.com/food/asian/pad-thai will direct to the food controller and the paid thai method within that controller, and also have a rule to send from www.mysite.com/food/asian/ to the food controller and asian index method??
The MVC design pattern isn't for rewriting URLs to point to folder structures. It can do this but it certainly isn't its main purpose. If you're trying to create a URL structure with static content, it might be easier to use the URL rewriting functionality built into IIS.
If you're creating a full MVC application, set up FoodController and DrinkController to serve up your views, for example:
public class FoodController : Controller
{
public ActionResult ViewDishByTag(string itemType, string itemTag)
{
// If an itemType is displayed without itemTag, return an 'index' list of possible dishes...
// Alternatively, either return a "static" view of your page, e.g.
if (itemTag== "pad-thai")
return View("PadThai"); // where PadThai is a view in your shared views folder
// Alternatively, look up the dish information in a database and bind return it to the view
return ("RecipeView", myRepo.GetDishByTag(itemTag));
}
}
Using the example above, your route might look a little like this:
routes.MapRoute(
"myRoute",
"{controller}/{itemType}/{itemTag}",
new
{
controller = UrlParameter.Required,
action = "ViewDishByTag",
itemtype = UrlParameter.Optional,
itemTag = UrlParameter.Optional
}
);
Your question doesn't contain much detail about your implementation, so if you'd like me to expand on anything, please update your question.

ASP.NET MVC routing: with querystring to one action, without to another

I need the following routes:
example.com/products
goes to a product categories page (e.g. cars, trucks, buses, bikes)
controller=Products, action=Categories()
example.com/products?a=1&b=2
goes to an index of all products in a particular category (e.g. Ford, Honda, Chevy)
controller=Products, action=Index(string a, string b)
The routes only differ on the querystring, and it seems that MVC ignores anything after the "?". So of course only one rule will ever get hit--the first one.
How do I differentiate between the two?
Edit: stated differently, I want two routes. Is it possible to use the querystring in the route or does MVC truly ignore it? Is there any way to hack it, or use a custom routing scheme of some kind, much like I can do custom binding and custom validation?
Introduce Parameters. ASP.NET MVC allows you to create 'pretty' URLs, and that's exactly what you should do here:
First, the route mappings:
routes.MapRoute(
"SpecificProducts",
"products/{a}/{b}",
new { controller = "products", action = "Categories" }
);
routes.MapRoute(
"ProductsIndex",
"products".
new { controller = "products", action = "Index" }
);
Then, the controller actions
public ActionResult Index()
{
}
public ActionResult Categories(string a, string b) //parameters must match route values
{
}
This will allow you to use a search-friendly URL and you don't have to worry about query string parameters.

Areas And Routes

I'm using areas everywhere and I'm wanting something like the following:
http://localhost/MyArea/MySection/MySubSection/Delete/20
Usually I access things by doing the following:
http://localhost/MyArea/MySection/MySubSection/20
But if I want to delete then I have to say
http://localhost/MyArea/MySection/DeleteEntryFromMySubSection/20
With routes, how do you do this? (the routes aren't realistic by the way, they're much more concise than this in my system)
EDIT: This is specifically related to the use of Areas, an ASP.NET MVC 2 Preview 2 feature.
It would depend on how your routes & controllers are currently structured.
Here's an example route you might want to use.
If you want to be able to call the following route to delete:
http://localhost/MyArea/MySection/MySubSection/Delete/20
And let's assume you have a controller called "MyAreaController", with an action of "Delete", and for the sake of simplicity let's assume section and subsection are just strings e.g.:
public class MyAreaController : Controller
{
public ActionResult Delete(string section, string subsection, long id)
{
Then you could create a route in the following way (in your Global.asax.cs, or wherever you define your routes):
var defaultParameters = new {controller = "Home", action = "Index", id = ""};
routes.MapRoute("DeleteEntryFromMySubSection", // Route name - but you may want to change this if it's used for edit etc.
"{controller}/{section}/{subsection}/{action}/{id}", // URL with parameters
defaultParameters // Parameter defaults
);
Note: I'd normally define enums for all the possible parameter values. Then the params can be of the appropriate enum type, and you can still use strings in your path. E.g. You could have a "Section" enum that has a "MySection" value.

Resources