MVC 5: Controller's action based routing - asp.net-mvc

Is there a way to have different routing based upon controller's action?
For example:
Default routing
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
this would make the url look like
localhost:/Home/{someaction}/{id}
if the controllers action is
public ActionResult SomeAction(int id)
{
return Content("Sup?");
}
but lets suppose I have this action
public ActionResult AnotherAction(Guid productCategoryId, Guid productId)
{
return content("Hello!");
}
if I don't have any custom routing then the route would look like
localhost:/Home/AnotherAction?productCategoryId=someGuidId&productId=someGuidId
but for this action if I want the route to look like
localhost/Home/AnotherAction/productCategoryGuidId/productGuidId
how would I do that?
I have added a custom route
routes.MapRoute(
name: "appointment",
url: "{controller}/{action}/{appointmentId}/{attendeeId}",
defaults: new {controller = "Home",action = "Index", appointmentId = "",attendeeId="" }
);
but how do I say a controller's action to use that route and not default route.
Also, I read there is attribute routing in MVC 5. Would this help in my case? How would I use it in my case?

Register your custom MapRoute before your default Route. The order of which come first counts in the table route.
Routes are applied in the order in which they appear in the RouteCollection
object. The MapRoute method adds a route to the end of the collection, which means that routes are generally applied in the order in which we add them.
Hope It will help

Related

Custom Routing not working in MVC5

First of all, I am very new to MVC and this is my first ever project.
I am trying to achieve the custom routing URL like the following:
http://mywebsite/MDT/Index/ADC00301SB
Similar to...
http://mywebsite/{Controller}/{Action}/{query}
In my RouteConfig.cs, I put the following
routes.MapRoute(
name: "SearchComputer",
url: "{controller}/{action}/{query}",
defaults: new { controller = "MDT", action = "Index", query = UrlParameter.Optional }
);
In My MDTController.cs, I have the following code
public ActionResult Index(string query)
{
Utils.Debug(query);
if (string.IsNullOrEmpty(query) == false)
{
//Load data and return view
//Remove Codes for clarification
}
return View();
}
But it's not working and I always get NULL value in query if I used http://mywebsite/MDT/Index/ADC00301SB
But if I used http://mywebsite/MDT?query=ADC00301SB, it's working fine and it hits the Controller Index method.
Could you please let me know how I could map the routing correctly?
You should add your MapRoute before default MapRoute, because order in RouteCollection is important
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
name: "SearchComputer",
url: "{controller}/{action}/{query}",
defaults: new { controller = "MDT", action = "Index", query = UrlParameter.Optional }
);
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
}
One issue that I have encountered is that placing your route below the default route will cause the default to be hit, not your custom route.
So place it above the default route and it will work.
A detailed explanation from MSDN:
The order in which Route objects appear in the Routes collection is significant. Route matching is tried from the first route to the last route in the collection. When a match occurs, no more routes are evaluated. In general, add routes to the Routes property in order from the most specific route definitions to least specific ones.
Adding Routes to an MVC Application.
You can change it to
routes.MapRoute(
name: "SearchComputer",
url: "MDT/{action}/{query}",
defaults: new { controller = "MDT", action = "Index", query = UrlParameter.Optional }
);

Identify tenant from the url in multi-tenant asp.net mvc application

I am creating a multi-tenant asp.net application. I want my url to follow
**http://www.example.com/test1/test2/**{tenantName}/{controller}/{action}
**http://www.example.com/test1/**{tenantName}/{controller}/{action}
**http://www.example.com/**{tenantName}/{controller}/{action}
Here the part of the url in bold is fixed (will not change)
{tenantName}=will be logical tenant instance.
I have followed this link
What will be the routing to handle this?
It's as simple as this:
routes.MapRoute(
"MultiTenantRoute", // Route name
"test1/test2/{tenantName}/{controller}/{action}/{id}", // URL with parameters
new { id = UrlParameter.Optional } // Parameter defaults, if needed
);
The part without braces must match. The parts inside the braces will be transfer into route data parameters. I've added an optional parameter id, as you usualy find in the controllers, but you can customize it. You can also give default values to tenantName, controller or action as usual.
Remember that routes are evaluated in the order they're registered, so you should probably register this route before any other.
EDIT after question update
You cannot specify a catch all parameter like this: {*segment} at the beginning of a route. That's not possible. ASP.NET MVC wouldn't know how many segments to include in this part, and how many to be left for the rest of the parameters in the route.
So, you need to add a route for each possible case,taking into account that the first route that matches will be used. So you'd need routes starting with extra parameters like this:
{tenanName}...
{segment1}{tenanName}...
{segment1}/{segment2}/{tenanName}...
Depending on the structre of the expected urls you may need to add constraints to ensure that the route is being correctly matched. This can be done passing a fourth parameter to thw MapRoute method. This is an anonymous class, like the deafults parameter, but the specified value for each parameter is a constraint. These constraints, on their simplest forma, are simply strings which will be used as regular expressions (regex).
If the expected URLs are extremely variable, then implement yout own routing class.
You could define the route as
routes.MapRoute(
name: "TennantRoute",
url: "test1/test2/{tenantName}/{controller}/{action}",
defaults: new { controller = "Home", action = "Index"}
);
and your action must take parameter with name tenantName because you may want make some decision based on that ...for example
public ActionResult Index(string tenantName)
{
return View();
}
example : http://localhost:19802/test1/test2/PrerakT/Home/Index
Please make sure you define this path above the default route for following urls to work
http://localhost:19802/test1/test2/PrerakT/
http://localhost:19802/test1/test2/PrerakT/Home/
http://localhost:19802/test1/test2/PrerakT/Home/index
What if I want test1 and test2 to be changeable ...
routes.MapRoute(
name: "TennantRoute",
url: "{test1}/{test2}/{tenantName}/{controller}/{action}",
defaults: new { controller = "Home", action = "Index" }
);
and
public ActionResult Index(string tenantName, string test1, string test2)
{
return View();
}
as per your update on the question
routes.MapRoute(
name: "TennantRoute1",
url: "test1/test2/{tenantName}/{controller}/{action}",
defaults: new { controller = "Home", action = "Index" }
);
routes.MapRoute(
name: "TennantRoute2",
url: "test1/{tenantName}/{controller}/{action}",
defaults: new { controller = "Home", action = "Index" }
);
routes.MapRoute(
name: "TennantRoute3",
url: "{tenantName}/{controller}/{action}",
defaults: new { controller = "Home", action = "Index" }
);
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);

How to get the different URL for action methods in single controller without controller name in URL?

I am working on a simple MVC website. In my project there is only one controller (Home) and 2 action methods in it (Index and Inner pages). Home action returns the view for home page and the Inner pages action returns the content for inner pages (inner pages uses the single template, so use the single view for all inner pages).
Now all I want is, if I run the project I got the menus like:
http://localhost:3000/Home/
http://localhost:3000/Home/Info/AboutUs
http://localhost:3000/Home/Info/Contact
But instead of above path I need paths like:
http://localhost:3000/Home/
http://localhost:3000/AboutUs
http://localhost:3000/Contact
without adding new controller and the url needs to call their corresponding action methods.
My routing file is
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = UrlParameter.Optional } // Parameter defaults
);
Could you please help me to achieve this?
You need to add a custom route to your routes table. But make sure you also keep the default route. For example, I've create below a custom route named "HomeRoute" while keeping the default one...
routes.MapRoute(
name: "HomeRoute",
url: "{action}",
defaults: new { controller = "Home", action = "Index" }
);
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
But, be aware that you need to define the action methods in the home controller since the default controller is set to "Home", if they are defined in a different controller then change the default controller
In other words, if your Home controller is defined as follows...
public class HomeController : Controller
{
public ActionResult Index(){...}
public ActionResult About(){...}
}
Then you can navigate to the About action with the following route...
sitename/About

Replace default parameter binding without default route values

I have an action in controller like:
public ActionResult Index(string ssn)
{
}
and default route values: {controller}/{action}/{id}
I don't want use url like /Home/Index?ssn=1234. I want use like /Home/Index/1234.
But I also don't want to add new route values for ssn parameter (or custom model binder).
Is there some complete attribute, like [ActionName] but for parameters?
Something like this:
public ActionResult Index([ParameterBinding("id")] string ssn)
{
}
As Darin & Rumi mentioned - there are no built-in attributes, however you can achieve the same affect (across multiple controllers/actions) with a single new Route using the RouteCollection.MapRoute constraints parameter on a single route.
The following route config will apply the "SSN" route to the Foo or Bar controller, any other controller will go through the Default route.
routes.MapRoute(
name: "SSN",
url: "{controller}/{action}/{ssn}",
defaults: new { controller = "Foo", action = "Index" },
constraints: new { controller = "(Foo|Bar)", action = "Index" }
);
// default route
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
Edit: Alternatively you could use the ActionParameterAlias library which seems to support what you initially requested.

MVC route, query parameters

Two simple mvc3 routes, username and a default catch all.
routes.MapRoute(
"Users",
"{username}",
new { controller = "User", action = "Index"}
);
routes.MapRoute(
"Default",
"{*url}",
new { controller = "Default", action = "Index" }
);
How do you make the user route accept any extra query parameters like /username?ref=facebook
This example just heads of to default route...
EDIT:
MY BAD, was a bit surprised by this as it shouldn't care about query parameters.
Solution = clean and rebuild project.
Update your first route as follow:
routes.MapRoute(
"Users",
"/username",
new { controller = "User", action = "Index"}
);
In your controller Action add a parameter "ref" so that it MVC automatically passes the query string "ref" to your controller.
Query string parameters like ?ref= are not part of the Route segment definition. For example, a route llike:
routes.MapRoute(
"Default",
"{controller}/{action}",
new { controller = "Home", action = "Index"}
);
Would still match a URL like: /Home/Index?ref=facebook.
So you don't have to change your routes to accommodate ad hoc Query String. Handling them in your Actions/Controller is a different story, because you will have to follow and CoC Convention over Configuration guidelines and match the Query String parameter in your Actions.
Add the parameter to the route, and don't forget to add it to your action.
I would suggest adding something to the beginning of the urls to make it a bit more specific (in case you add any other routes to your project)
Example
routes.MapRoute(
"Users",
"users/{username}/{ref}",
new { controller = "User", action = "Index", ref = UrlParameter.Optional }
);
and in your action you'd want
public ActionResult Index(ref)
{
if (string.IsNullOrEmpty(ref))
{
//TODO: add your logic here
}
}
This should accept /users/someusername/facebook.com OR /users/someusername?ref=facebook.com

Resources