ASP.NET MVC Dynamic Action with Hyphens - asp.net-mvc

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.

Related

Html.RenderAction with Route Name

I am trying to utilize the Route attribute naming (ex: [Route(Name = "Abc123")]) in a controller action, and likewise be able to call that via Html.RenderAction, but it appears that this does not support route names. I assume this is because route names are reserved only for ones requested via HTTP and not called directly, but somewhat new to MVC so I'm at a loss.
I'm using MVC Attribute Routing entirely, and I do not have routes configured otherwise. It seems that I must define the route name, and the route name has to match the action method name. In doing so, however, I am getting naming conflicts when I try to name more than one Index.
I'm basically trying to support multiple partial views, each having their own controller, which serve as plugins/widgets on my site. So ideally each would have an action called Index.
Do you have a recommendation on how I can maintain the same naming? This allows me to call Html.RenderAction("Index", [ControllerName], [Model]) without the render name changing.
You can use attribute routing with Html.RenderAction just you have to make sure that the action name in attribute is actual Name :
[Route("Home/About")]
public ActionResult About()
{
ViewBag.Message = "Your application description page.";
return View();
}
and in HTML you can have
#{Html.RenderAction("About", "home");}
It will work fine.
You should be able to do what you are trying to do with attribute routing. If you are trying to render a partial view you should be using RenderPartial instead of RenderAction.
Are you doing this between areas? I believe there are some gotcha's with making that work correctly.
Can you please post example Controller code and RouteConfig?

What do the curly braces mean in a route in MVC?

I'm setting up my routes with an MVC project but im a little confused about the curly braces...
If I have...
routes.MapRoute( "Music", "Music/{name}", new { } );
What is the purpose of the curly braces around name, does this get passed to something? Or does this map to something if I pass a default object in?
They are parameter names that are used in routing requests. For example the default route defines three of them:
{controller}/{action}/{id}
controller and action parameters are for finding your controller action. id parameter can be used as an input in those actions.
When you define a custom route you have to provide controller and action parameters. If they are not defined in your URL, you should provide default values so MVC knows what action to run when a request matches that route.
routes.MapRoute("Music",
"Music/{name}",
new { controller="Music", action="SomeAction" });
Other parameters like id or name like you defined can be used to provide input to actions. In your example, name parameter is passed to matching action like this:
public ActionResult SomeAction(string name)
{
//do something
}
The curlybraces indicate a kind of named wildcard.
The "Music/Index" route will only match the URL Music/Index and nothing else
The "Music/{Name}" route will match any URLs starting with Music, and having anything after the slash. It will match both the URLs Music/metallica and Music/madonna.
With the curly brace, you'll be able to pick up "metallica" or "madonna" from the above URLS as routevalues.
As a final example: With ASP.NET MVC, there's always a standard route. {controller}/{action}/{id}. This route will catch URLs like Music/genre/rock or Product/edit/5.
The resulting routevalues for these two will be:
controller=music, action=genre and id=rock for the first one
controller=product, action=edit and id=5 for the last one.
I'll try to provide a less contrived example.
Routes in ASP.NET MVC are placed into a dictionary, and when there's an incoming request, the MVC pipeline looks at the request and tries to determine what Controller and Action to route it to.
So let's say I have the following controllers: Home, Forum, and Article
And while we're at it, let's say I have the following actions: View, Edit, Create on both the Forum and Article controllers.
Those braces allow me to create one route for both:
routes.MapRoute("Viewing",
{controller}/{action}/{id},
new {controller = "Article", action="" }, //The article controller has precedence
new { controller = "Article|Forum" } //contrived for this example
);
Those braces mean that whatever controller they put in (as long as it's Article or Forum based on the Constraints), the same route works. This keeps me from having to have a route for each and every action in the Forum and Article controller.
I could have just as easily made two routes:
routes.MapRoute("Articles",
article/{action}/{id},
new {controller = "Article" } //The article controller has precedence
);
routes.MapRoute("Forums",
forum/{action}/{id},
new { controller = "forum" }
);
But there's duplication there that doesn't need to be there.
Routes are also pretty tricky things, in that order matters. The top route will be evaluated before the bottom route. If it matches the top route's structure, it will go to that action, even if that's not the right action.
Phil Haack has a Route Debugger that helps with this. And I've also taken his source code and modified it so that you can make it a control and put it on all your pages as a partial (and hopefully you will also put code on there that would only allow internal folks to see it).

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.

Avoiding the Controller with Routing Rules in ASP.NET MVC

I've created a website with ASP.NET MVC. I have a number of static pages that I am currently serving through a single controller called Home. This creates some rather ugly URLs.
example.com/Home/About
example.com/Home/ContactUs
example.com/Home/Features
You get the idea. I'd rather not have to create a controller for each one of these as the actions simply call the View with no model being passed in.
Is there a way to write a routing rule that will remove the controller from the URL? I'd like it to look like:
example.com/About
example.com/ContactUs
example.com/Features
If not, how is this situation normally handled? I imagine I'm not the first person to run in to this.
Here's what I've done previously, using a constraint to make sure the shortcuts don't conflict with other routing rules:
routes.MapRoute(
"HomeShortcuts",
"{action}",
new { controller = "Home", action = "Index" },
new { action = "Index|About|ContactUs|Features" }
);
Add defaults for the controller names in the new statement. You don't have to have {controller} in the url.

How do you change the controller text in an ASP.NET MVC URL?

I was recently asked to modify a small asp.net mvc application such that the controler name in the urls contained dashes. For example, where I created a controller named ContactUs with a View named Index and Sent the urls would be http://example.com/ContactUs and http://example.com/ContactUs/Sent. The person who asked me to make the change wants the urls to be http://example/contact-us and http://example.com/contact-us/sent.
I don't believe that I can change the name of the controller because a '-' would be an illegal character in a class name.
I was looking for an attribute that I could apply to the controller class that would let me specify the string the controller would use int the url, but I haven't found one yet.
How can I accomplish this?
Simply change the URL used in the route itself to point to the existing controller. In your Global.asax:
routes.MapRoute(
"Contact Us",
"contact-us/{action}/",
new { controller = "ContactUs", action = "Default" }
);
I don't believe you can change the display name of a controller. In the beta, the controller was created using route data "controller" with a "Controller" suffix. This may have changed in RC/RTM, but I'm not sure.
If you create a custom route of "contact-us/{action}" and specify a default value: new { controller = "ContactUs" } you should get the result you are after.
You need to configure routing. In your Global.asax, do the following:
public static void RegisterRoutes(RouteCollection routes)
{
...
routes.MapRoute(
"route-name", "contact-us/{action}", // specify a propriate route name...
new { controller = "ContactUs", action = "Index" }
);
...
As noted by Richard Szalay, the sent action does not need to be specified. If the url misses the .../sent part, it will default to the Index action.
Note that the order of the routes matter when you add routes to the RouteCollection. The first matched route will be selected, and the rest will be ignored.
One of the ASP.NET MVC developers covers what Iconic is talking about. This was something I was looking at today in fact over at haacked. It's worth checking out for custom routes in your MVC architecture.
EDIT: Ah I see, you could use custom routes but that's probably not the best solution in this case. Unless there's a way of dealing with the {controller} before mapping it? If that were possible then you could replace all "-" characters.

Resources