Add a route priority for Asp. Net MVC and WebApi

Source: Internet
Author: User

Add a route priority for Asp. Net MVC and WebApi
I. Why do we need the routing priority? We all know that we are using the Asp. net MVC project or WebApi project, the registered route has no priority. when the project is large, or has multiple regions, or multiple Web projects, or is developed using a plug-in framework, our route registration is probably not written in a file, but distributed in many files of different projects. As a result, the priority of the route is highlighted. For example: App_Start/RouteConfig. routes in cs. mapRoute (name: "Default", url: "{controller}/{action}/{id}", defaults: new {controller = "Home", action = "Index ", id = UrlParameter. optional}); Areas/Admin/AdminAreaRegistration. cs context. mapRoute (name: "Login", url: "login", defaults: new {area = "Admin", controller = "Account", action = "Login", id = UrlParameter. optional}, namespaces: new string [] {"Wenku. admin. controllers "}); if the above general default route is registered first, and then the login route is registered, then in any case, the first qualified route will be matched first, that is, the registration of the second route is invalid. The reason for this problem is the order of registration of the two routes, and Asp. net MVC and WebApi do not have the concept of priority. Therefore, we need to implement this idea on our own today and add a concept of priority when registering a route. Ii. solution 1. Analyze the ingress of Route registration. For example, create a project named 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 entry points for registering the Mvc route:. areaRegistration. registerAllAreas (); register region route B. RouteConfig. registerRoutes (RouteTable. A registered project route entry for WebApi routing registration: WebApiConfig. register (GlobalConfiguration. configuration); register a WebApi Route 2. Register a route processing class analysis AreaRegistrationContext RouteCollection HttpRouteCollection when registering a route, these three classes are mainly used to register and process the route. 3. Route Priority Scheme a. Modify ingress entry B. Customize the RoutePriority and HttpRoutePriority of a route, both classes have the Priority attribute c. You can customize a RegistrationContext to register the route. The registered object is the preceding custom route. D. After all the routes are registered, they are added to the RouteCollection and HttpRouteCollection in priority order. Iii. Specific implementation 1. Routing 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 router registration interface
public interface IRouteRegister{    void Register(RegistrationContext context);}

 

3. Define 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);    }    public RoutePriority MapRoute(string name, string url, object defaults, int priority = 0)    {        return MapRoute(name, url, defaults, (object)null /* constraints */, priority);    }    public RoutePriority MapRoute(string name, string url, object defaults, object constraints, int priority = 0)    {        return MapRoute(name, url, defaults, constraints, null /* namespaces */, priority);    }    public RoutePriority MapRoute(string name, string url, string[] namespaces, int priority = 0)    {        return MapRoute(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 belonging 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[] namespaces,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 List<HttpRoutePriority> HttpRoutes = new List<HttpRoutePriority>();    public HttpRoutePriority MapHttpRoute(string name, string routeTemplate, int priority = 0)    {        return MapHttpRoute(name, routeTemplate, defaults: null, constraints: null, handler: null, priority: priority);    }    public HttpRoutePriority MapHttpRoute(string name, string routeTemplate, object defaults, int priority = 0)    {        return MapHttpRoute(name, routeTemplate, defaults, constraints: null, handler: null, priority: priority);    }    public HttpRoutePriority MapHttpRoute(string name, string routeTemplate, object defaults, object constraints, int priority = 0)    {        return MapHttpRoute(name, routeTemplate, defaults, constraints, handler: null, priority: priority);    }    public HttpRoutePriority MapHttpRoute(string name, string routeTemplate, object defaults, object constraints, HttpMessageHandler handler, int priority = 0)    {        var httpRoute = new HttpRoutePriority();        httpRoute.Name = name;        httpRoute.RouteTemplate = routeTemplate;        httpRoute.Defaults = defaults;        httpRoute.Constraints = constraints;        httpRoute.Handler = handler;        httpRoute.Priority = priority;        HttpRoutes.Add(httpRoute);        return httpRoute;    }    #endregion}

 

4. Add the route Registration 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 registration entry in the Global. asax. cs file
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 a custom route }}

 

In each project, you only need to inherit the custom route registration interface IRouteRegister, for example:
Public class regiister: IRouteRegister {public void Register (RegistrationContext context) {// Register the backend management logon 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 default route context on the backend Management page. 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 mobile 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 [] {"Wenku. mobile. http "}}, constraints: new {action = new StartWithConstraint ()}, priority: 0 );}}

 

4. Summary: This is an Asp. net Mvc has a very small function expansion, and small projects may not need this function. However, sometimes the project's registered route does not take effect, you should think of it because of the routing order, in this case, the routing priority function may bring convenience to you. In short, share it with friends in need for reference.

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.