I'm using ASP.NET with MVC4. In a simple controller I wish to use a URL such as
www.sitename.com/controller/action/param1/param2/param3
Can I do this?
The controller would be ControllerController and have a method
Action(param1, param2, param3)
etc
Yes, just add a route such as:
routes.MapRoute(name: "MyRoute", url: "{controller}/{action}/{p1}/{p2}/{p3}");
If you want it for a specific controller then you can use "hard" names instead of the {controller} and {action} placeholders.
Make sure you add this before the more specific routes though (i.e. before the "Default" route).
You may also find the RouteDebugger on NuGet helpful.
Related
Is it possible to define a route in Symfony 2.x that dynamically resolves the action based on part of the route ?
Example :
rest_localite:
path: /rest/localite/{_action}
defaults: { _controller: ApplicationLocaliteBundle:Rest:{_action}, _format: json }
Thank you very much
This was considered bad practice as it exposes internal parts of the application and last I heard they removed it.
If you are doing this to save time you might want to look at the #Route annotations for actions, it is less of a pain.
But if you really cannot do without dynamic actions calls and do not mind the risk you could try passing the action's name as a parameter to a single controller method that then calls the appropriate method.
I'm working on a Symfony2 project and am trying to figure out how to pass parameters from the route configuration to the controller. I know I can configure default values in the route configuration, and retrieve the values in the controller using the appropriate var name in the function declaration, but that isn't exactly what I want.
My use case is the following. I have a standard method in my controller that I want to access from 2 or 3 different routes. Depending on which route is being called, I want to "configure" the method differently. I can accomplish this in a few ways:
In my controller, check the route name using `$this->container->get("request")->get("_route"), but that is ugly, and then I am hardcoded to the route name. Moves configuration to the controller, which should just be logic - not configuration.
Create a base controller class, and subclass each method for my different routes. Each subclassed method would then have the necessary configuration within the method. Cleaner soln than #1, but still "heavy" in the sense of having multiple classes for a simple need and still pushes configuration data into the business logic.
Put configuration data into the route configuration. In the controller, access the configuration data as required. Ideal solution, but don't know how.
I can use the route default array to specify my arguments, but then must make sure to use a regex to ensure that the params are not overridden at the URL level (security risk). This is functional, but still kinda cludgy and not a pretty hack.
I presume that there must a better way to do this, but I can't seem to figure it out. Is there a way to access the routing object from the controller, and access the different configuration parameters?
You can pull the actual route from the router service. Something like:
$routeName = $this->container->get("request")->get("_route");
$router = $this->container->get("router");
$route = $router->getRouteCollection()->get($routeName);
Not sure if this would be such a great design though. Consider passing a $configName to your controller method, adding a parameter with the same name in a config file then using getParameter to access it. That would eliminate the route stuff from the equation.
Something like:
zayso_arbiter_import:
pattern: /import
defaults: { _controller: ZaysoArbiterBundle:Import:index, configName: 'someConfigName' }
public function importAction(Request $request, $configName)
I would like to create a route that looks something like this:
routes.Add(new Route("{*url}/{action}.do/{id}", new MvcRouteHandler())
Is this possible? It seems like the catchall has to be last?
The catch-all has to be the last parameter in the route, as it says "match the entirety of what remains of the URL."
You could fake it, though, by having just the catchall and using a custom MyRouteHandler instead of the MvcRouteHandler. Your custom route handler would just manipulate the RouteContext to split the action and id back out of the URL before passing it to the MvcRouteHandler for processing.
From ScottGu:
The MVC framework chooses the
Controller to use by evaluating the
RouteTable rules in the order that
they have been registered
I think you can register after the catch-all, but it won't ever be hit because the catch-all will be hit first.
I recently want to have a special routing rule : {*whatever}/details/{Id}/{itemName}
I know an exception will be thrown once I run the application. In my application, for example my url pattern is www.domain.com/root/parent/child/.../child/details/30/itemname
but the current routing doesnot support this. How can custom the routing handler to make it work?
A class has been written that supports this
I've written such a class that can handle catch-all segment anywhere in the URL. There's quite some code to it, but it works as expected and I've used it on a real life project.
Check it out yourself and see if it fulfils your needs.
The problem is... how will it know when to stop?
the {*whatever} segment will match:
/foo/
/foo/bar
/foo/bar/details/4/moreFoo
/foo/bar/andmore/details/4/moreFoo
Because the catch-all parameter includes anything, it will never stop.
The only way to implement this would be to create a different route for each place you use details...
eg:
games/details/{id}/{itemName}
widgets/details/{id}/{itemName}
books/details/{id}/{itemName}
Of course, that is already provided in the default {controller}/{action}/{id} route
I think you may want to look at extending the System.Web.Routing.RouteBase class and override the GetRouteData() method. With it you can look at the requested url and decide if matches your pattern and if so construct and return a new instance of RouteData that points to the controller and action that you want to handle the request. Otherwise if you don't match the requested url you return null.
See the following for examples:
Pro ASP.NET MVC Framework
By Steve Sanderson
Custom RouteBase
I would like to create routing rules like the following:
www.app.com/project/35/search/89/edit/48 ---> action is edit in the project controller
The passed variables should be project# (35), search# (89), and edit#(48)
Can someone help me structure a routes.MapRout() for this.
I want to use:
routes.MapRoute(
"Default",
"{controller}/{projectid}/search/{searchid}/{action}/{actionid}",
new { controller = "Home", action = "Edit", projectid = "", actionid = "" }
);
But from previous experience, this type of MapRoute will fail... I've only gotten something in the following format to work:
{controller}/{action}/{variable}
Can anyone give me any advice on this? Thanks.
Honestly, it sounds like you need to make you URL's look like this:
www.app.com/project/35?search=89&edit=48&flag=63
It would make your like much simpler.
Grouping Controllers with ASP.NET MVC
A question that often comes up is how do you group controllers when building a large application with ASP.NET MVC. Often, the question is phrased as whether or not ASP.NET MVC supports “Areas”, a feature of Monorail. According to the Monorail documentation,
MonoRail supports the concept of areas, which are logical groups of controllers. All controllers belong to an area. The default area is an empty (unnamed) one
While there’s no out of the box support for this in ASP.NET MVC, the extensibility model allows building something pretty close.
Registering Routes
The first thing we do is call two new extension methods I wrote to register routes for the areas. This call is made in the RegisterRoutes method in Global.asax.cs.
routes.MapAreas("{controller}/{action}/{id}",
"AreasDemo",
new[]{ "Blogs", "Forums" });
routes.MapRootArea("{controller}/{action}/{id}",
"AreasDemo",
new { controller = "Home", action = "Index", id = "" });The first argument to the MapAreas method is the Routing URL pattern you know and love. We will prepend an area to that URL. The second argument is a root namespace. By convention, we will append “.Areas.AreaName.Controllers” to the provided root namespace and use that as the namespace in which we lookup controller types.
http://haacked.com/archive/2008/11/04/areas-in-aspnetmvc.aspx
Why did this format fail for you? What do you mean by "failed"? If it just didn't work, try placing your new MapRoute above the default commands - the Routes collection is working in a FIFO manner.
#Robert Harvey - Take a look at Basecamp for example - they are using a very similar approach in their URI's. I think it's a much cleaner and better approach than what you're suggesting. It's not even "Simpler" once you get the hang of routing.