In an ASP.NET MVC 5 web application, there is a RouteConfig class that registers many routes. In all of the examples I have seen so far, only the "Default" route has a non-empty name. The URL pattern and default route values seem to be sufficient to correctly associate any URL to the controller and action to execute. So, is there any benefit to naming a route? For debugging or logging? Just for self-documenting the code?
For example:
public class RouteConfig
{
public static void RegisterRoutes( RouteCollection routes )
{
routes.IgnoreRoute( "{resource}.axd/{*pathInfo}" );
// Most pages.
routes.MapRoute( name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "home", action = "index", id = UrlParameter.Optional }
// A special page.
// Should the route have a name?
routes.MapRoute( name: "",
url: "special",
defaults: new { controller = "special", action = "index", HttpVerbs = HttpVerbs.Get } );
}
}
The main reason to name a route is so that if you need a link to a route from somewhere in the app, you can reference the name. That way if the actual URL/path changes you don't break everywhere in the code that references that route.
Related
I'm using ASP.NET MVC 5
I'm having issues with both routes and parameters.
I have this function in my ControllerBase
[HttpGet]
[Route("~/obtenerAngulos/{Conex_AT}/{Conex_BT}")]
public JsonResult obtenerAngulos(string Conex_AT, string Conex_BT)
{
return Json(
new
{
AT = Conex_AT,
BT = Conex_BT
}
, JsonRequestBehavior.AllowGet);
}
And I start having problems receiving the second parameter Conex_BT the Url.Action() returns this route http://localhost:53645/Base/obtenerAngulos?Conex_AT=Y&Conex_BT=y the problem, is Conex_BT is always null
Then I try to work with route and add the Data Anotation for it [Route("~/obtenerAngulos/{Conex_AT}/{Conex_BT}")] but with Url.Action() I keep getting the same route as before.
Even if I try to write it manually like http://localhost:53645/Base/obtenerAngulos/AA/BB I get
HTTP Error 404.0 - Not Found
I mention both problems because I'm pretty sure they are relationated.
Here is the route configuration
RouteConfig.cs
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
}
Make sure you have enabled attribute routing on the route collection.
//enable attribute routes
routes.MapMvcAttributeRoutes();
//convention-based routes
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
This now means that the following should match obtenerAngulos/y/x
public class ControllerBase: Controller {
//Matches obtenerAngulos/y/x
[HttpGet]
[Route("~/obtenerAngulos/{Conex_AT}/{Conex_BT}")]
public JsonResult obtenerAngulos(string Conex_AT, string Conex_BT) {
//...
}
}
The tilde (~) on the method attribute is used to override any route prefixes if needed.
Routes are matched in the route table in the same order they are added. In your example you had convention based routes registered before attribute routes. Once a route is matched it no longer looks for other matches.
Reference Attribute Routing in ASP.NET MVC 5
I want to change this
localhosht:3220/MyController/MyAction?id=1
to this
localhosht:3220/myText/MyController/MyAction?id=1
So that it works any time, even in redirection, routing or other cases.
Thanks.
Just add the text to the route url:
routes.MapRoute(
name: "Default",
url: "myText/{controller}/{action}"
);
You can do it with a custom route to match your desired uri. In the RegisterRoutes method of RouteConfig, add the following.
The order is important here, if you add the "Default" route before the "MyText" route, then MyText route will not be hit.
//for your custom route that starts with "myText"
routes.MapRoute(
name: "MyText",
url: "myText/{controller}/{action}/{id}",
defaults: new { controller = "MyController", action = "MyAction", id = UrlParameter.Optional }
);
//for other normal routes
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
While adding a route with the url parameter of myText/{controller}/{action}/{id} (above your default route) will certainly work, if your intention is to use the myText frequently, you might also want to take a look at the concept of areas.
By default, in your Global.asax, in your Application_Start() function, you have a call for the method:
AreaRegistration.RegisterAllAreas();
What this does is to look for a special Areas folder in your project, and register each folder under it that has a class that extends from AreaRegistration and overrides the RegisterArea function. Similar to your RouteConfig.cs, this class can look like this:
public class MyTextAreaRegistration : AreaRegistration
{
public override string AreaName
{
get
{
return "MyText";
}
}
public override void RegisterArea(AreaRegistrationContext context)
{
context.MapRoute(
name: "MyText_default",
url: "MyText/{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
}
note: you can create Areas in your MVC project by scaffolding: Just right click on your project and Add.. -> Area. Everything will be done for you automatically.
In the end, Areas provide a more permanent solution to your MyText/SomeController/SomeAction needs. For a detailed article, you can check this.
routes.MapRoute(
name: "Default",
url: "{myText}/{controller}/{action}/{id}"
defaults: new {
controller = "Home",
action = "Index",
id = UrlParameter.Optional,
myText= UrlParameter.Optional
);
It will work for you if you want to use parameter like myText to make your Url Seo friendly.
I have a controller called "StuffController" with a parameterless Index action. I want this action to be called from a URL in the form mysite.com/stuff
My controller is defined as
public class StuffController : BaseController
{
public ActionResult Index()
{
// Return list of Stuff
}
}
I added a custom route so the routes are defined like this:
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
// Custom route to show index
routes.MapRoute(
name: "StuffList",
url: "Stuff",
defaults: new { controller = "Stuff", action = "Index" }
);
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
}
But when I try to browse to mysite.com/stuff I get an error
HTTP Error 403.14 - Forbidden
The Web server is configured to not list the contents of this directory.
The URL mysite.com/stuff/index works fine. What I am doing wrong?
HTTP Error 403.14 - Forbidden The Web server is configured to not list the contents of this directory.
The error indicates that you have a virtual directory (probably a physical one) in your project called /Stuff. By default, IIS will first reach this directory and look for a default page (for example /index.html), and if no default page exists will attempt to list the contents of the directory (which requires a configuration setting).
This all happens before IIS passes the call to .NET routing, so having a directory with the name /Stuff is causing your application not to function correctly. You need to either delete the directory named /Stuff or use a different name for your route.
And as others have mentioned, the default route covers this scenario so there is no need for a custom route in this case.
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
// Passing the URL `/Stuff` will match this route and cause it
// to look for a controller named `StuffController` with action named `Index`.
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
}
It seems that your scenario is covered fine by default route, so there is no need for a custom Stuff one.
As to why the error is thrown, the fact that action is listed in defaults does not mean that it is actually becoming a part of a route. It should be mentioned in the route, otherwise it appears as there is no action at all. So what I think happens here is that first route is matched, but it cannot be processed as there is no action specified, so MVC passes request on to IIS, which throws the named error.
The fix would be simple:
// Custom route to show index
routes.MapRoute(
name: "StuffList",
url: "Stuff/{action}",
defaults: new { controller = "Stuff", action = "Index" }
);
But again, you shouldn't need that at all.
I haven't used .NET Routing before.
I have a URL: http://myurl.com/Account/Login/?IsIPA=true.
I want to be able to hit this URL with the following: http://myurl.com/IPA
This is the only custom route I want hit.
Can I create a route just for a single URL like this?
My code that isn't working is:
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapMvcAttributeRoutes();
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
routes.MapRoute("IPA", "Account/Login/{IsIPA}", new { controller = "Account", action = "Login", IsIPA = "true" });
}
I get the error:
The constraint entry IsIPA on the route with route template Account/Login/{IsIPA}=True must have a string value or be of a type which implements System.Web.Routing.IRouteConstraint.
Route matching is similar to a switch case statement. The url parameter and any default values and constraints are all considered to determine whether or not it is a match with the incoming URL. If the route matches, it will then create a dictionary of route values based on the configuration. If the route does not match, the next route in the collection is tried until a match is found (or not).
This means the order that routes are specified is important. The default route matches any URL with 0, 1, 2, or 3 segments. Therefore, in most cases you will need to define your custom route before the default route.
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapMvcAttributeRoutes();
routes.MapRoute(
name: "IPA",
url: "IPA",
defaults: new { controller = "Account", action = "Login", IsIPA = "true" });
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
}
The above configuration will route http://myurl.com/IPA to the Controller named Account and Action method named Login, and pass the additional route key IsIPA. This same URL will be built for the Controller/Action/IsIPA combination because it is the first one that matches in the list.
Note that the original URL http://myurl.com/Account/Login/?IsIPA=true will still work and still route to the same location. This configuration just adds an extra route to that resource.
Without testing it, I think that you want this:
routes.MapRoute("IPA", "Account/Login/{IsIPA}",
new { controller = "Account", action = "Login", IsIPA = "true"});
I am having problems setting up the RouteConfig file to accept an optional record ID as part of the URL like in the examples below.
http://localhost/123 (used while debugging locally)
or even
http://www.foobar.com/123
Ideally, I would like to have the record ID (123 as in the examples above) be passed in as a parameter to the Index view of the Home controller. I had thought that the default routeconfig would suffice for this (using the ID as an optional element), but apparently the application is apparently trying to direct the browser to a view called '123' which obviously doesn't exist.
My current RouteConfig.cs looks like this:
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
}
Any assistance on this would be greatly appreciated.
Your routing says:
{controller}/{action}/{id}
that's your site then your controller, then your action and then an id.
You want just site then id:
routes.MapRoute(
name: "Default",
url: "{id}",
defaults: new { controller = "Default", action = "Index", id = UrlParameter.Optional }
);
This would then hit a controller at
public class DefaultController : Controller
{
public ActionResult Index(int id)
{
}
}
"{controller}/{action}/{id}" tells MVC that a route may have a controller name, or it may have a controller name followed by an action name, or it may have those two followed by an ID. There's no way, given just an ID, for the routing to understand that it's supposed to be an ID and not an action or a controller name.
If you're never planning to have any other controllers or actions, something like this might work:
routes.MapRoute(
name: "Default",
url: "{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
But that's probably a bad idea. Pretty much every site has at least one key word to indicate what the ID represents. For example, StackOverflow has "/questions/{id}".