Webapi add area to support unlimited levels of controller with the same name

Source: Internet
Author: User

Original: Webapi add area to support unlimited level controller with the same name

Microsoft's WEBAPI default implementation logic

A controller with the same name is not supported in the default implementation, otherwise it will be reported httperror on the Internet, and various routing self-implementations are found on the web.

Controller classification for ASP.

Set of problems encountered when building MVC and WEBAPI project frameworks

With the help of the above address, according to the requirements, rewrite the areahttpcontrollerselector, the routing principle and the above address is similar, are through the route matching stitching FullName, and then match the closest apicontroller, and the so-called closest, This means that if more than one match is obtained based on the name of the stitching, get the apicontroller with the fewest number of namespace nodes to ensure that the routing rules are registered multiple times. The controller can be matched in a way from complex to simple (it is important to note that Areahttpcontrollerselector is the controller as the end of the split point), for example:

Assume that the following route matching rules are registered (the controller, the webapi of the action, and the character of the route)

           Config. Routes.maphttproute (                name: "Defaultareaapi",                routetemplate: "Api/{area}/{controller}/{action}/{id}",                defaults:new {id = routeparameter.optional}            );            Config. Routes.maphttproute (                name: "Defaultapi",                routetemplate: "Api/{controller}/{action}/{id}",                defaults: New {id = routeparameter.optional}            );
In the controller directory, there are multiple layers of controllers with the same name and different levels, such as:

Controller/area/samecontroller, the corresponding namespace is Controller.Area.SameController
Controller/samecontroller, the corresponding namespace is Controller.samecontroller

By Api/area/same/get will match to Controller/area/samecontroller
By Api/same/get will match to Controller/samecontroller

The rewritten areahttpcontrollerselector can support an infinite hierarchy of areas, as long as the namespace is supported, as opposed to the reference URL, such as

"Api/{area1}/{area1}/{area2}/{area3}/{controller}/{action}/{id}"


The following is the specific Areahttpcontrollerselector code

Using system;using system.collections.generic;using system.linq;using system.text;using System.Threading.Tasks; Using system.web;using system.web.http.dispatcher;using system.net.http;using system.web.http;using System.web.http.controllers;using system.net;namespace webapi{///<summary>//Represents a area system.web. Http.Dispatcher.IHttpControllerSelector instance//</summary> public class Areahttpcontrollerselector:defa        Ulthttpcontrollerselector {private readonly httpconfiguration _configuration; <summary>///Lazy all Ihttpcontroller reflection collection contained in the current assembly, TKey for lowercase controllers///</summary> P        Rivate readonly lazy<ilookup<string, type>> _apicontrollertypes; Private ilookup<string, type> apicontrollertypes {get {return This._ap            Icontrollertypes.value; }}///<summary>//Initializes a new instance of the ISAhttpcontrollerselector class///</summary>//<param name= "Configuration" ></param>            Public Areahttpcontrollerselector (httpconfiguration configuration): Base (configuration) {            this._configuration = Configuration; This._apicontrollertypes = new lazy<ilookup<string, type>> (this.        Getapicontrollertypes); }///<summary>//Get current assembly Ihttpcontroller reflection Collection///</summary>//<returns&gt ;</returns> private ilookup<string, type> getapicontrollertypes () {Iassembliesresolv Er assembliesresolver = this._configuration.            Services.getassembliesresolver (); Return this._configuration. Services.gethttpcontrollertyperesolver (). Getcontrollertypes (Assembliesresolver). ToLookup (t = T.name.tolower (). Substring (0, t.name.length-defaulthttpcontrollerselector.controllersuffix.length), t = = t); }//<summary>//Selects a System.Web.Http.Controllers.HttpControllerDescriptor for the given Syste        M.net.http.httprequestmessage.        </summary>//<param name= "Request" ></param>//<returns></returns> public override Httpcontrollerdescriptor Selectcontroller (Httprequestmessage request) {Httpcontrolle            Rdescriptor des = null; String controllername = this.            Getcontrollername (Request); if (!string. Isnullorwhitespace (Controllername)) {var groups = this.                Apicontrollertypes[controllername.tolower ()]; if (groups! = null && groups.                    Any ()) {string endstring; var routedic = Request. Getroutedata ().                        values;//existence controllername words must be able to take ihttproutedata if (Routedic.count > 1) { StringBuilder tmp = new StringbuildeR (); foreach (var key in Routedic.keys) {tmp.                            Append ('. '); Tmp.                            Append (Routedic[key]); if (key.                            Equals (Defaulthttpcontrollerselector.controllersuffix, Stringcomparison.currentcultureignorecase))                            {//If control, represents the end of the namespace break; }} tmp.                        Append (Defaulthttpcontrollerselector.controllersuffix); endstring = tmp.                    ToString (); } else {endstring = string. Format (". {                    0}{1} ", Controllername, Defaulthttpcontrollerselector.controllersuffix); }//Take the minimum number of namespace nodes type var type = groups.                        Where (t = T.fullname.endswith (endstring, Stringcomparison.currentcultureignorecase)). (t = = T.fullname.count (s = = = ')). FirstOrDefault ()///default returns the least number of namespace nodes for the first if (type! = null) {des                    = new Httpcontrollerdescriptor (this._configuration, controllername, type); }}} if (des = = null) {throw new httpresponseexception (re Quest. Createerrorresponse (Httpstatuscode.notfound, String. Format ("No route providing a controller name is found to match request URI ' {0} '", request.)            (RequestUri)));        } return des; }    }}

The usage is to replace the registration in the Application_Start method of the global file

GlobalConfiguration.Configuration.Services.Replace (typeof (Ihttpcontrollerselector),                                                   new Areahttpcontrollerselector (                                                       globalconfiguration.configuration));


Webapi add area to support unlimited levels of controller with the same name

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.