MVC Routes With Embedded IDs - asp.net-mvc

We want to have a route that looks like this:
/account/123/dosomething/234
In this case, account would be the controller and requesttrafficid would be the action, I guess. I am assuming I can define this route like this:
{controller}/{accountId}/{action}/{id}
In this case, the two IDs just become parameters of the action.
The question is: can do something like this for Web API?
Our normal MVC controllers are just returning views and other static content.
All of our data comes from the API.
We want our routes to be as close as possible, something like this:
api/account/123/dosomething/234
Based on my understanding, account wouldn't be the API controller, it would be dosomething. The two IDs just become parameters again. But how do I define this route? Do I just hard-code the 'account' part?

If you're only concern is being able to make the action portion of the route the same, you have two choices:
You're not required to use the naming convention of [Method]Action. If you don't follow this convention, you just need to specify which method applies with the appropriate attribute:
// These are functionally equivalent:
public JsonResult GetSomething(int id) { ... }
[HttpGet]
public JsonResult DoSomething(int id) { ... }
If you want to follow convention, but you want to customize the action name for routing purposes, you can use the ActionName attribute:
[ActionName("dosomething")]
public JsonResult GetSomething(int id) { ... }

With AttributeRouting, this is a piece of cake: http://attributerouting.net. You just put the placeholders at the right spot in your URL and MVC handles the rest.

Related

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.

Combining values in ASP.Net Routes for MVC

Can anyone suggest a way to accomplish the following in ASP.Net Routing (for MVC 3)?
I want to have URLs where the value which determines the controller is actually part of the id for the page:
/{id}-{controller}/{action}/{further-values}
But I need the id value to include the value used for the controller as well, so in the above if we have the following URL:
/chelsea-football-team/view/2010-2011
I want the {id} value to, ideally, be "chelsea-football-team", the controller to be "football-team", the action to be "view" and the additional value to be "2010-2011".
I have no issues having several routes with the controller value hard coded into the route definition, but I need to be able to have several controller values.
I know that I can simply combine the values in the controller, but that adds a lot of additional, repeated code - so is this accomplishable in any other way?
Why do I want to do this? Because I need to have the team name in full, but part of the team name will always match the controller name so why not combine them in the route?
I want the {id} value to, ideally, be "chelsea-football-team", the controller to be "football-team", the action to be "view" and the additional value to be "2010-2011".
...MapRoute(null, "{id}/{action}/{*furtherValues}",
new {
controller = "FootballTeam",
});
Update after comment 1
You can't combine route parameters in a URL such that a single parameter represents both a variable (id) and a controller, using the standard routing implementation. If you want the id to be "chelsea-football-team", that has to be a self-contained route parameter. You can't combine it in a way that MVC extracts the controller name from the id.
To meet this requirement, you may have to create a custom RouteBase implementation:
public class MyCustomRoutingPattern : RouteBase
{
public override RouteData GetRouteData(HttpContextBase httpContext)
{
// do your coding and return an instance of RouteData
}
}
You would then use it like so:
routes.Add(new MyCustomRoutingPattern(
"{id}/{action}/{*furtherValues}"));
Your RouteBase implementation can then extract the controller from the id parameter. The Pro ASP.NET MVC3 Framework book by Steve Sanderson and Adam Freeman has a section on how to override the RouteBase class.

MVC 3 Route question

I'm trying to put in some new routes but not sure where to start. What I would like to do is to have my routes translate as follows:
/transport class A/23 translated to /info/classes/A-23
I understand the basics of using MapRoute but can I do things like the above?
I hope someone can give advice.
This seems to me that you're actually after something like UrlRewrite since you're going from one Url to another.
But MVC doesn't rewrite Urls - it maps them to controller actions based on route patterns you provide.
So, if you're asking if you can split up the first url to a controller/action pair (with parameters) then of course you can. You just set up a route with the necessary parameters in the right place. So you could call MapRoute with something like (I would use hyphens for the spaces):
/*route pattern:*/ "transport-class-{class1}/{class2}"
/*with route defaults:*/ new { controller = "Info", action = "ViewInfo" }
Then you could write a controller as follows:
public class InfoController : ControllerBase
{
public ActionResult ViewInfo(string class1, string class2)
{
//presumably get model data from the class parameters here
//and pass it as parameter to below:
return View();
}
}
Although it would depend also if the transport and class constants in this route are actually also variable I guess - in which case you could push those down as route parameters, and into the parameter list of your controller method.

Refactoring my route to be more dynamic

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.

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