This is an annoyance that I've experienced for a long time, but now my client is asking me to address it.
In every route that gets generated (by a non-Default route), a query string value gets appended: "Area="
As an example:
// RouteConfig.Register():
routes.MapRoute(
"ProfileDetails",
"{slug}",
new { controller = "Profile", action = "Details" }
);
routes.MapRoute(
"Default",
"{controller}/{action}/{id}",
new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
To generate a URL to the BadgeController.Index action, the Default route will be applied and the result will be /Badge... and that's what is expected.
But to generate a URL to the ProfileController.Details(someUser) action, the ProfileDetails route will be applied and the result will be /someUser?Area= ... which will work, but the ?Area= is unnecessary and messy.
I have no areas in my project. How do I get rid of that Area= query string value? This happens with all of my routes that are not the predefined Default route, not just the "ProfileDetails" one in this example.
I've tried removing the AreaRegistration.RegisterAllAreas() from my Global.asax file, since I assume it's not required.
Related
I have default routing set for my mvc application like:
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = UrlParameter.Optional } // Parameter defaults
);
I have Home controller with Index() and About(). Tell me please how to modify routing to get both domain.com/Index and domain.com/About urls?
Thank you
Add this before your default route. By adding it before the default route, if it matches it will be used to set the RouteDictionary values. Untested, but it should map urls that only have a single component that is either index or about. Note, that this assumes you don't have an index or about controller. The routing constraint is important as it keeps it from matching on each controller's index action, e.g., controller/.
routes.MapRoute(
"IndexOrAbout",
"{action}",
new { controller = "home", action = "index", id = "" },
new
{
action = "(index)|(about)"
}
);
Note, if you need to expand this to more top-level routes or make it more dynamic you could use a custom routing constraint that could draw the top-level values from a database or configuration. At that point, you'd probably want to change it from using the action parameter to the id parameter and have a single action that use the id to determine what to show rather than have an action per value.
I have tried routes.mapRoute but i can't figure a way in MVC 3 to use it make a root path route to an action. e.g mywebsite.com/party should redirect to mywebsite.com/events/party where events is the controller and party is the action.
Is this even possible?
Without seeing your existing routes, its hard to give you an exact solution.
One rule to keep in mind:
MVC will resolve the first in your route collection that matches the requested URL
not necessarily the most specific match.
Make sure you do not have another rule that would also satisfy that route placed earlier in your code, e.g. the routing algorithm might be finding a "party" controller and "index" action because you have a default rule like:
routes.MapRoute(
"Default",
"{action}",
new { controller = "Home", action = "Index" }
);
placed before your rule.
You need to put something like
routes.MapRoute(
"PartyRoute",
"party",
new { controller = "Events", action = "Party" }
);
BEFORE any route that might match a URL with just a single parameter
routes.MapRoute(
"Default",
"{action}",
new { controller = "Events", action = "Index" }
);
Global.asax.cs has the following code on initialization:
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = UrlParameter.Optional } // Parameter defaults
);
What I'm asking is, how does it know that what it gets for "{controller}" will be the name of the Controller class to be invoked? Are there tokens defined somewhere? if so, can I list them?
If I define additional tokens (like "{lang}") will it assume they are additional parameters?
(I'm developing a custom URL rewrite/redirect handler, and I need it to work with MVC...)
What is the most practical way to define custom patterns and "aliases" for URLs?
The Mvc runtime has the controller and action tokens hardcoded. In addition there is also "area" but thats about it.
#TDaver If I define additional tokens (like "{lang}") will it assume they are additional parameters?
yes. If you define, for instance, a parameter like lang, it wil detect it. Think about like that, it will be the querystring field called lang of the page. and you can create a route for a pretyy url. Like below;
routes.MapRoute(
"Default", // Route name
"{lang}/{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = UrlParameter.Optional } // Parameter defaults
);
so the url will be like ; http://example.com/en/home/about
Also, the most important part of routing is to understand that the routes will be picked by order. for instance, if you have multiple routes matching your current request, the first route will be picked by MVC Framework.
I reccomend you to have a look at phil haccked's RouteDebugger
Also you can create route constraints for advanced routing options as well.
I'm at a loss as to why my routes are conflicting. I have these in my Global.asax file:
routes.MapRoute(
"CustomerView", "{controller}/{action}/{username}",
new { controller = "Home", action = "Index", username = "" }
);
routes.MapRoute(
"Default", "{controller}/{action}/{id}",
new { controller = "Home", action = "Index", id = "0" }
);
So far everything has worked fine except when I created a controller action like so:
public ActionResult MyAction(int id)
{
//Do stuff here
return View();
}
When I try viewing it through http://mydomain/MyController/MyAction/5 I get:
Server Error in '/' Application.
The parameters dictionary contains a
null entry for parameter 'id' of
non-nullable type 'System.Int32' for
method 'System.Web.Mvc.ActionResult
Track(Int32)' in
'InTouch.Controllers.OrderController'.
To make a parameter optional its type
should be either a reference type or a
Nullable type. Parameter name:
parameters
suggesting to me that the id value is not being read properly. Sure enoguh, when I swap the order of the routes around it works fine. My (admittedly limited) understanding so far was that, if a variable name specified in a route matches that specified in a controller action definition, it will assume that one regardless of order. Apparently I was wrong. Swapping the order causes other controller actions to break. What is the right way to handle my routes in this instance?
The problem with your example is that the match is happening on the first route and it's seeing "5" as the username parameter. You can use constraints to limit what values are accepted for each parameter to accomplish what you're wanting. Since the "Default" route that accepts an Id is more restrictive than the "CustomerView" route, I would list the "Default" route first with a constraint on the Id parameter:
routes.MapRoute(
"Default", "{controller}/{action}/{id}",
new { controller = "Home", action = "Index", id = "0" },
new { id = #"\d+" }
);
This will cause the first route to only match if Id is an integer value. All other requests would then fall through to the "CustomerView" route that would pick up any other requests that didn't have integers as that third parameter.
Check out Creating a Route Constraint for an explanation of constraints.
My (admittedly limited) understanding
so far was that, if a variable name
specified in a route matches that
specified in a controller action
definition, it will assume that one
regardless of order.
The binding of route values to action arguments happens AFTER the framework determines which route to use. Route selection is performed using a "first match wins" heuristic: the first route that can successfully match the incoming request is used, even if a "better" route was defined later.
Michael's solution is correct. You need to list the Default route first, using route constraints to only match URLs where the ID is numeric. Your second, less restrictive route should come next.
NOTE: If you follow Michael's solution you'll run into problems if you have any users with a username consisting only of numbers. You might consider adding some other discriminating factor to the routes, like putting the keyword "user" in the 2nd one:
routes.MapRoute(
"Default", "{controller}/{action}/{id}",
new { controller = "Home", action = "Index", id = "0" },
new { id = #"\d+" }
);
routes.MapRoute(
"CustomerView", "{controller}/{action}/user/{username}",
new { controller = "Home", action = "Index", username = "" }
);
I'm trying out ASP.NET MVC routing and have of course stumbled across a problem. I have a section, /Admin/Pages/, and this is also accessible through /Pages/, which it shouldn't. What could I be missing?
The routing code in global.asax:
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
"Pages", // Route name
"Admin/Pages/{action}/{id}", // URL with parameters
// Parameter defaults
new { controller = "Pages", action = "Index", id = "" }
);
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
// Parameter defaults
new { controller = "Home", action = "Index", id = "" }
);
}
Thanks!
I'd suggest adding an explicit route for /Pages/ at the beginning.
The problem is that it's being handled by the Default route and deriving:
controller = "Pages"
action = "Index"
id = ""
which are exactly the same as the parameters for your Admin route.
For routing issues like this, you should try out my Route Debugger assembly (use only in testing). It can help figure out these types of issues.
P.S. If you're trying to secure the Pages controller, make sure to use the [Authorize] attribute. Don't just rely on URL authorization.
You could add a constraint to the default rule so that the {Controller} tag cannot be "Pages".
You have in you first route {action} token/parameter which gets in conflict with setting of default action. Try changing parameter name in your route, or remove default action name.