First, why need routing priority
We all know that we have no priority in registering routes in an ASP. NET MVC project or Webapi project, and when a project is larger, or has multiple regions, or multiple Web projects, or is developed with a plug-in framework, our route registrations are probably not written in a single file. Instead, the problem of routing priorities is highlighted by the spread of files in many different projects.
For example: in App_start/routeconfig.cs
Routes. MapRoute ( name: "Default", URL: "{controller}/{action}/{id}", defaults:new {controller = "Home", action = "Index", id = urlparameter.optional});
In Areas/admin/adminarearegistration.cs
Context. MapRoute ( name: "Login",
URL: "Login", defaults:new {area = "Admin", controller = "Account", action = "Login", id = urlparameter.optional},< C7/>namespaces:new string[] {"Wenku.Admin.Controllers"});
If it is to register the above generic default route, and then register the login route, then no matter what, will first match the first one to satisfy the condition of the route, that is, the two route registration is invalid.
This is caused by the order of the two route registrations, and the notion that registered routes in ASP. NET MVC and Webapi do not have a priority, so today we are going to implement this idea by adding a priority concept when registering a route.
Second, the solution of ideas
1, first analyze the entrance of the route registration, for example, we create a new mvc4.0 project
public class mvcapplication:system.web.httpapplication{ protected void Application_Start () { Arearegistration.registerallareas (); Webapiconfig.register (globalconfiguration.configuration); Filterconfig.registerglobalfilters (globalfilters.filters); Routeconfig.registerroutes (routetable.routes); }}
There are two registry entries for MVC routes:
A. Arearegistration.registerallareas (); Registering zone routes
B. routeconfig.registerroutes (routetable.routes); Registering Project Routes
The WEBAPI route registration entry has one:
Webapiconfig.register (globalconfiguration.configuration); Registering WEBAPI routes
2. Processing class analysis of registered route
AreaRegistrationContext
RouteCollection
Httproutecollection
When you register a route, it is primarily the three classes that register the processing route.
3. Route priority scheme
A. Change the registration entry for a route
b, customize the structure of a route class routepriority and Httproutepriority, these two classes have the priority attribute below
C, custom a registrationcontext to register the route, the registered object is the above custom route.
D, all routes are registered and then added in order of precedence to routecollection and httproutecollection to actually take effect.
Third, the concrete realization
1. Route definition
public class routepriority:route{Public string Name {get; set;} public int priority {get; set;} Public routepriority (string url, Iroutehandler routehandler) : Base (Url,routehandler) { }}public class httproutepriority{public string Name {get; set;} public int priority {get; set;} public string Routetemplate{get;set;} public object Defaults{get;set;} public object Constraints{get;set;} Public Httpmessagehandler Handler{get;set;}}
2, define the interface of the route registration
public interface irouteregister{ void Register (Registrationcontext context);
3. Defining the routing Registration Context class
public class registrationcontext{#region MVC public list<routepriority> Routes = new List<routepriority> ;(); Public routepriority MapRoute (string name, String Url,int priority=0) {return MapRoute (name, URL, (object) null /* defaults */, priority); Routepriority MapRoute (string name, string URL, object defaults, int priority = 0) {return MapRoute (Name, URL, defaults, (object) NULL/* constraints */, priority); Routepriority MapRoute (string name, string URL, object defaults, object constraints, int priority = 0) { Return MapRoute (name, URL, defaults, constraints, NULL/* namespaces */, priority); Routepriority MapRoute (string name, string URL, string[] namespaces, int priority = 0) {return MapR Oute (name, URL, (object) NULL/* defaults */, namespaces, priority); } Public routepriority MapRoute (string name, string URL, object defaults, string[] Namespaces,int priority=0) { Return MapRoute (name, URL, defaults, NULL/* constraints */, namespaces, priority); } Public routepriority MapRoute (string name, string URL, object defaults, object constraints, string[] namespaces, int Priority = 0) {var route = Mappriorityroute (name, URL, defaults, constraints, namespaces, priority); var areaname = getareaname (defaults); Route. datatokens["area" = areaname; Disabling the namespace lookup fallback mechanism keeps this areas from accidentally picking up//controllers B Elonging to other areas bool Usenamespacefallback = (namespaces = = NULL | | namespaces. Length = = 0); Route. datatokens["Usenamespacefallback"] = Usenamespacefallback; return route; } private static string Getareaname (object defaults) {if (defaults! = null) {var property = Defaults. GetType (). GetProperty ("area"); if (Property! = null) return (string) property. GetValue (Defaults, null); } return null; } Private routepriority Mappriorityroute (string name, string URL, object defaults, object constraints, string[] Namespa Ces,int priority) {if (url = = null) {throw new ArgumentNullException ("url"); } var route = new Routepriority (URL, new Mvcroutehandler ()) {name = name, priority = Priority, Defaults = Createroutevaluedictionary (Defaults), Constraints = Createroutevaluedictionary ( constraints), Datatokens = new RouteValueDictionary ()}; if (namespaces! = null) && (namespaces. Length > 0)) {route. Datatokens["namespaces"] = namespaces; } routes.add (route); return route; } private static RouteValueDictionary Createroutevaluedictionary (object values) {var dictionary = values as Idictionary<string, object>; if (dictionary! = null) {REturn New RouteValueDictionary (dictionary); } return new RouteValueDictionary (values); } #endregion #region http public list4. Add the route registration processing method to the configuration class
public static Configuration registerroutepriority (this Configuration config) {var typessofar = new list<type> (); var assemblies = Getreferencedassemblies (); foreach (Assembly Assembly in assemblies) {var types = Assembly. GetTypes (). Where (t = = typeof (Irouteregister). IsAssignableFrom (t) &&!t.isabstract &&!t.isinterface); Typessofar.addrange (types); } var context = new Registrationcontext (); foreach (var type in Typessofar) {var obj = (irouteregister) activator.createinstance (type); Obj. Register (context); } foreach (var route in context.) httproutes.orderbydescending (x = x.priority)) GlobalConfiguration.Configuration.Routes.MapHttpRoute (route. Name, route. Routetemplate, route. Defaults, route. Constraints, route. Handler); foreach (var route in context.) routes.orderbydescending (x = x.priority)) RouteTable.Routes.Add (route. Name, route); return config;} private static Ienumerable<assEmbly> getreferencedassemblies () {var assemblies = buildmanager.getreferencedassemblies (); foreach (Assembly Assembly in assemblies) yield return Assembly;}
In this way, you only need to modify the original registered entry in the Global.asax.cs file to
public class mvcapplication:system.web.httpapplication{ protected void Application_Start () { Webapiconfig.register (globalconfiguration.configuration); Filterconfig.registerglobalfilters (globalfilters.filters); Routeconfig.registerroutes (routetable.routes); Configuration.instance () . Registercomponents () . Registerroutepriority (); Register custom Route }}
In each project, you use only the irouteregister that you want to inherit from the custom route registration interface, for example:
public class registration:irouteregister{public void register (Registrationcontext context) {//Registered backend management login route Context. MapRoute (Name: "Admin_login", url: "Admin/login", defaults:new {area = "Admin", controller = "Account", action = "Login", id = urlparameter.optional}, namespaces:new string[] {"Wenku.Admin.Controllers" }, Priority:11); Register the backend Admin page by default route context. MapRoute (Name: "Admin_default", url: "Admin/{controller}/{action}/{id}", Defaults:new { Area = "Admin", controller = "Home", action = "Index", id = urlparameter.optional}, namespaces:new string[] {"Wenku.Admin.Controllers"}, Priority:10); Register the phone to access the WEBAPI routing context. Maphttproute (Name: "Mobile_api", Routetemplate: "Api/mobile/{controller}/{action}/{id}", defaults:new {area = "mobile", action= routeparameter.optional, id = routeparameter.optional, namespacename = new string[] {"Wen Ku. Mobile.http "}}, constraints:new {action = new Startwithconstraint ()}, priority:0 ); }}
Iv. Summary
This is a small feature of ASP. NET MVC, small projects may not need this feature, but sometimes when the project is large, the registered route does not take effect when you should think that it is possible because of the routing order, the function of this route priority will be able to bring you convenience. In short, share to the friends who need reference.
Add route priority to ASP. NET MVC and Webapi