MVC route, query parameters - asp.net-mvc

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

Related

MVC Additional Custom routes

I want to implement a custom route in my MVC app and I just can't get it to work. I want to keep the exist default route as specified when you create your MVC app.
The routes I want to be valid should look like this:
default: /{controller}/{action}/{id}
new custom: /{controller}/{appid}/{action}/{id}
With the custom domain, I will be passing the appid in with every request, but the {id} should be optional. The routes are thus defined as follow:
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Updates", action = "Index", id = UrlParameter.Optional }
);
routes.MapRoute(
name: "NewPackageRoute",
url: "{controller}/{appid}/{action}/{id}",
defaults: new { controller = "apps", appid = "00000000000000000000", action = "Index", id = UrlParameter.Optional }
);
On the AppsController, I have an action method Index:
public ActionResult Index(string appid, string id)
If I supply the id parameter, this action method is hit as expected. I am expecting this method to also be called if the {id} parameter is not supplied, thus leaving the id parameter as null. This however does not happen.
How should I define my route differently? Should I perhaps rather make use of AttributeRouting for achieve my goal?
I should maybe also add... If I call the Search action on the Apps controller, I can get to the action. This would happen through the default route...
Hope I have all and enough info...
Oh my, but I guess I should've tried before I posted this. I left this issue for a day and now I got it working without any effort...
Thanks #StephenMuecke. You did point out the ordering of the routes which I forgot about. I played with the order initially, but at that point I had other issues in the route definitions that caused it not to work.
All I added was as length check on the appid route value and it is working... My routes are defined as follow now:
routes.MapRoute(
name: "NewPackageRoute",
url: "apps/{appid}/{action}/{id}",
defaults: new { controller = "Apps", action = "Index", id = UrlParameter.Optional },
constraints: new { appid = #"^[a-zA-Z0-9]{20}" }
);
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Updates", action = "Index", id = UrlParameter.Optional }
);

How to map same routes for two controller?

I have two controller in my MVC application. One is Home controller and other is User controller. I am using following RouteConfig settings.
routes.MapRoute(
"actiononly",
"{action}/{id}",
new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
routes.MapRoute(
"Default",
"{controller}/{action}/{id}",
new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
I want abc.com/Blog
abc.com/Login
Instead of abc.com/Home/Blog
abc.com/User/Login.
Above configuration works fine with abc.com/Blog but it is not working with abc.com/Login.
How to remove controller name from the link for both controllers?
Also how can I only show abc.com when website launches instead of abc.com/index? I am using following code in my webpage to access the particular page.
#Html.ActionLink("Home", "Blog", "Home")
#Html.ActionLink("Login", "Login", "User")
Your default route should automatically cater for wanting to nav to abc.com without requiring the index part of the URL
You need to ensure that your main route is specified as the default:
context.MapRoute(
"Site_Default",
"{controller}/{action}/{*id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
If you want to map short routes you can do exactly what you've done above. I use this helper function in my own project to map short routes:
void ShortRoute(string action, string controller)
{
ShortRoute(action, controller, action);
}
void ShortRoute(string action, string controller, string route)
{
_context.MapRoute(route, route, new { action, controller });
}
With usage:
ShortRoute("About", "Home");
Which allows me to navigate to mywebsite.com/about instead of mywebsite.com/home/about
If it's not working for certain URLs it may be that the route handler is matching a different route - I believe it does depend on the order you register them
There's a good route debugging plugin you can use
https://www.nuget.org/packages/routedebugger/
It gives you a summary of all routes and which ones matched the current URL - very useful
Without bringing in additional packages, you simply need to add an additional route. To create the new route, you first must define what you want your URL to be. In this case, you have said you want to be able to go to /Login which is on the user controller. Ok - let's create a new route. This route should be located ABOVE your default route.
routes.MapRoute(
"UserLogin",
"Login/{id}",
new { controller = "User", action="Login", id = UrlParameter.Optional }
);
The first parameter is simply the route name. The second parameter is the format of the URL that I want this route to match. Given we know what action we want to match to this route, we don't need the {action} or {controller} catchall placeholders that are in the default route. Also note that we can declare what controller this route will hit without having to specify the controller in the URL.
Last note, you don't have to have the {id} be part of the route if you will never be passing an ID parameter to that function. If that is the case, then you can safely remove any references to id in the UserLogin route.
As I re-read your question, you should be able to do this for some of your other examples as well. Let's take the /About URL and demonstrate the removal of the {id} parameter.
routes.MapRoute(
"AboutUsPage",
"About",
new { controller = "Home", action="About"}
);
This is very simple. You just need to create a route for each of your expected URLs.
Keep in mind that if you don't pass the controller or action as a URL placeholder, you will need to do so manually by providing them as default values.
routes.MapRoute(
"Blog",
"Blog/{id}",
new { controller = "Home", action = "Blog", id = UrlParameter.Optional }
);
routes.MapRoute(
"Login",
"Login/{id}",
new { controller = "User", action = "Login", id = UrlParameter.Optional }
);
routes.MapRoute(
"Default",
"{controller}/{action}/{id}",
new { controller = "Home", action = "Index", id = 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 }
);

MVC 5: Controller's action based routing

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

Routes: multiple parameters for the application root

I am trying to set up my MVC application with the root as follows:
mysite.com/ -> Index action
mysite.com/thingID -> to CurrentThing action
mysite.com/thingID/year -> to CurrentThing action
Action: public ActionResult CurrentThing(string thingID, int year)
I also need the regular controller/action route to work both with and without an id. ThingID is a string. I have the following routes defined:
routes.MapRoute(
"Regular",
"{controller}/{action}/{id}",
new { id = UrlParameter.Optional }
);
routes.MapRoute(
"RootSpecificRecord",
"{thingID}/{year}",
new { controller = "Things", action = "CurrentThing", year = DateTime.Now.Year }
);
routes.MapRoute(
"Root",
"",
new { controller = "Things", action = "Index" }
);
This works fine until I go to mysite.com/id/year at which point the first route treats the id as a controller and the year as an action. How can I resolve this?
The routing engine is unable to tell the difference between
/{controller}/{action}/{id} and /{ThingId}/{year}
Since your id parameter is optional, and you don't have any constraints that ThingId is an id.
You could try putting the RootSpecificRecord route first, and altering the Id so that it will only accept an integer. This will make it so it's more specific than your regular route. Assuming ofcourse that thingID is an integer, you could alter your route like this:
routes.MapRoute(
"RootSpecificRecord",
"{thingID}/{year}",
new { controller = "Things", action = "CurrentThing", year = DateTime.Now.Year },
new {thingID= #".*\d+.*" }
);
See this blog post about route constraints, if you want to create a different constraint.
Default route must be last in your route tables

Resources