How to create wildcard controller in ASP.NET MVC? - asp.net

In a default application ASP.NET MVC 3.0 app I have a controller with Index() and Details(string id) methods. These map to /orders/ and orders/details/ORDER_ID_HERE. How do I change the routing so that Details maps to orders/ORDER_ID_HERE, and continue to have Index() serve up a default index page?

If you would add a new route to you route collection like:
routes.MapRoute(
"Detailed", // Route name
"{contoller}/{id}", // URL with parameters
new { controller = "Orders", action = "Details", id = UrlParameter.Optional } // Parameter defaults
);
It would work, but you break a lot of things, a url like [site]/Home/Search for instance would result in a:
System.ArgumentException: The parameters dictionary contains a null entry for parameter 'id' of non-nullable type 'System.Int32' for method 'System.Web.Mvc.ActionResult Details(Int32)' in 'MvcApplication3.Controllers.OrdersController'.
The reason for this is that /Home/Search matches the route {controller}/{id}.
An other, similar way to solve it would be:
routes.MapRoute(
"Detailed", // Route name
"order/{id}", // URL with parameters
new { controller = "Orders", action = "Details", id = UrlParameter.Optional } // Parameter defaults
);
Make sure that the static part in the route, order, does not match the name of your actual orders controller, otherwise you'll have the same problem, rendering [url]/orders unreachable with an System.ArgumentException instead of calling the Index() method (the default route)
The negative side of this approach is that you'll need to do this for every controller where you would like to have such functionality.

Try adding this route before the default route:
routes.MapRoute("SomeName", "{controller}/{id}", new { controller = "Orders", action = "Details" });
Notice how the {action} has been removed from the URL parameter.

Related

How can be home controller define as root also when action have params? asp.mvc 4

By default if url is 'mydomain' it go to controller home; action = index.
But when index action has params the url have to be:
mydomain/home/index?name=John
want to get:
mydomain?name=John
What should be define for create such url?
Thanks,
Yosef
The correct url is the following:
http://mydomain.com/?name=John
Given default route setup this will invoke the Index action on Home controller and pass the name parameter.
As far as your request about the mydomain?name=John url is considered, well, this doesn't look quite a well formed url.
Are you sure you want mydomain/home/index?name=John and mydomain?name=John as your urls in your site?
If you corrected your routing engine, your routes could be, mydomain/home/index/john and mydomain/john, which to me would be more correct.
Is that what you're going for?
If so, assuming you have a Index action, accepting a string parameter of name in your home controller, you could modify your global.asax, and change the default route, and add a route below the standard default route like this:
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", name= UrlParameter.Optional } // Parameter defaults
);
routes.MapRoute(
"NameOnly", // Route name
"{name}", // URL with parameters
new { controller = "Home", action = "Index" } // Parameter defaults
);
Be sure you put the name only route at the bottom, as a string based parameter will match everything, so you need to match the more explicit ones first.

Am I approaching routes in my application wrong?

I'm working on my first ASP.NET MVC 3 application and I've got a couple of actions defined to handle adding/removing an ice cream from a menu. They look like so:
[HttpPost]
public PartialViewResult AddMenuIceCreamMapping(int iceCreamId, int menuId)
[HttpPost]
public PartialViewResult RemoveMenuIceCreamMapping(int iceCreamId, int menuId)
In order for these actions to not result in a 404 error, I went into the Global.asax.cs file and added the following:
routes.MapRoute(
"AddMenuIceCreamMapping", // Route name
"IceCream/AddMenuIceCreamMapping/{iceCreamId}/{menuId}", // URLwith parameters
new
{
controller = "IceCream",
action = "AddMenuIceCreamMapping",
iceCreamId = UrlParameter.Optional,
menuId = UrlParameter.Optional
}
);
routes.MapRoute(
"RemoveMenuIceCreamMapping", // Route name
"IceCream/RemoveMenuIceCreamMapping/{iceCreamId}/{menuId}", // URLwith parameters
new
{
controller = "IceCream",
action = "RemoveMenuIceCreamMapping",
iceCreamId = UrlParameter.Optional,
menuId = UrlParameter.Optional
}
);
and those work, meaning I can click an Add or Remove button on my page and add or remove an ice cream/menu mapping. Great. But I'm expecting that there will be more situations like this and I can see this routes container having more entries such as these. And to my novice web programmer eye, it seems a bit clunky and I begin to think that perhaps I'm going about this the wrong way. Am I? Is there a better way to approach this so that I don't end up doing the "go create some action that takes N parameters and then go add a route" thing. Any suggestions here?
You can use placeholders in your mappings to deal with this... Instead of what you've got above, you could use this (note that I don't specify a default):
routes.MapRoute(
"TwoParameterRoute", // Route name
"{controller}/{action}/{id1}/{id2}", // URL with parameters
);
And if you have to add a route that takes three parameters, you extend the idea:
routes.MapRoute(
"ThreeParameterRoute", // Route name
"{controller}/{action}/{id1}/{id2}/{id3}" // URL with parameters
);
In a controller for the two parameter route, the code would look like this (for a contrived sample):
public ActionResult Index(int id1, int id2)
{
ViewData["id1"] = id1;
ViewData["id2"] = id2;
return View();
}
One final thing to note is that you can change the naming to match a pattern you might have. In the first example, instead of id1 and id2 you might have entityId and relatedId or something similar.
You know that you can also use querystring parameters even with POST requests? Using just the default route (that comes with new ASP.NET MVC projects), you can reach your actions with /IceCream/AddMenuIceCreamMapping/?iceCreamId=1&menuId=1 and /IceCream/RemoveMenuIceCreamMapping/?iceCreamId=1&menuId=1.
Using querystringparameters also show that this url is a parameterized method call, and not a reference to a resource, as the original URLs would indicate.
If your set of CRUD actions will be repeating with every custom Entity that you introduce in your application, then you can have the controller as a parameter too. As it is now, you have controller fixed. Also I would avoid such long action names. I would also avoid spelling Icecream as IceCream. Just coz of its looks.
Probably you should have a controller Menu, which handles Icecreams. It kinda doesn't make sense that Icecream handles its own things because it is a part of something else.
Such as
routes.MapRoute(
"RemoveIcecreamFromMenu", // Route name
"menu/remove-icecream/{iceCreamId}/{menuId}", // URLwith parameters
new
{
controller = "Menu",
action = "RemoveIcecream",
iceCreamId = UrlParameter.Optional, // i don't think those two should be optional
menuId = UrlParameter.Optional
}
);
But it makes sense for an Icecream controller to handle its own CRUD:
routes.MapRoute(
"CreateIcecream", // Route name
"icecream/create", // URLwith parameters
new
{
controller = "Icecream",
action = "Create"
}
);
routes.MapRoute(
"DeleteIcecream", // Route name
"icecream/delete/{id}", // URLwith parameters
new
{
controller = "Icecream",
action = "Delete",
id = #"\d+" // this tells the routing engine only integer are accepted
}
);
I would go with something that had descriptive urls and no default route:
routes.MapRoute(
"IceCreamEdit", // Route name
"{controller}/{action}/icecream/{iceCreamId}/menu/{menuId}" // URLwith parameters
);

ASP.NET MVC - double action execution

I've got a website running on ASP.NET MVC 2 - on one action I have some code running and then returning ANOTHER view than the action's name. i.e - action1 will return view "view2".
Somehow, action1 runs one time, then calls
return View("view2",model)
and runs again, for the second time.
Why is this so? and can it be fixed?
EDIT: added some code
Action:
public ActionResult View1(int id, int id2) {
// some code ...
return View("View2", u);
}
where as View2 has nothing to do with View1 or the action (just needed for display).
Route:
routes.MapRoute(
"Default", // Route name
"{action}/{id}", // URL with parameters
new { controller = "Main", action = "Index", id = UrlParameter.Optional } // Parameter defaults
);
routes.MapRoute(
"View1", // Route name
"View1/{id}/{id2}", // URL with parameters
new { controller = "Main", action = "View1" } // Parameter defaults
);
Link:
http://<some server>/View1/15/fb
Thanks.
Put your default route at the bottom. Routes are evaluated top to bottom so ...
http://<some server>/View1/15/fb
... gets evaluated by the default route as Controller = Main, Action = View1
I have been having the same problem like you.
There are some possible reasons they are producing this double action execution. There you are some useful links:
MVC controller is being called twice
ASP.NET MVC Action is Called Twice
In my case was an extension for chrome called "HTML Validator 1.3.3". This extension was calling the action again. (I guess to do the validation)

where to use route-name of routing in aspnet mvc

i'm new to routing in aspnet mvc.. i have following code:
Action Controller
public ActionResult SchoolIndex()
{
return View(SchoolRepository.GetAllSchools());
}
here is the routing
routes.MapRoute(
"School", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "School", action = "SchoolIndex", id = "" } ); // Parameter defaults
when i enter "localhost/school" in addressbar, it is giving 404 error instead it should route to my "schoolIndex" action
i have given route-name as "School" where it is used ?
You can't specify a route name in a URI, ever.
Route names are for, e.g., Html.RouteLink(). RouteLink allows you to specify exactly the route you want, even if it's not the first matching route for the arguments you pass.
URIs are matched in order. The first matching route wins.
Read my post on routing for much more detail.

Problem with globalization of ASP.NET MVC routes

I tried to use the solution explained at http://weblogs.asp.net/paulomorgado/archive/2010/01/31/web-site-globalization-with-asp-net-routing.aspx to localize my application using the language parameter in my routes.
Here's the code I have in my Global.asax:
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.Add("en", new Route("en/{*path}", new GlobalizationRouteHandler(CultureInfo.GetCultureInfo("en-US"))));
routes.Add("fa", new Route("fa/{*path}", new GlobalizationRouteHandler(CultureInfo.GetCultureInfo("fa-IR"))));
routes.MapRoute(
"AdminHome",
"{language}/admin",
new { controller = "Admin", action = "Index" }
);
}
But when I point my browser to /en/admin or /fa/admin I receive a 404 error message.
I tried this one too:
routes.MapRoute(
"AdminHome",
"admin",
new { controller = "Admin", action = "Index" }
);
But still a 404 error for /en/admin - (in this case "/admin" works.)
Any idea?
I have a very similar route pattern in my own MVC site.
routes.MapRoute(
"BlogSpecific", // Route name
"{blogSubFolder}/{controller}/{action}", // URL with parameters
new { blogSubFolder = "", controller = "", action = "Index" } // Parameter defaults
);
The two main differences that I can see are that I specify the {action} in my route, and I also call out the first route param as a parameter in my object ("blogSubFolder = "",").
Now I just did some testing, and I found the same behavior that you are seeing, I take out the {action} out of my route and I get a 404. But if I specify the action everything works out.
Ok, so I created a new project, with the default route, and I don't have to specify the action, it defaults to Index just like I'd expect it to. I then add a new route where I specify the controller {language}/Foo/{action}, and I continue to get errors if I don't include the index in my url. Long story short, As near as I can tell if your route has a variable that precedes the controller you have to specify the action in your url.

Resources