Controller classification for Asp.net Web APIs

Source: Internet
Author: User

This article describes the design concept of restful Web APIs: Understanding and Design of restful Web APIs

Next, this article describes how to create a "pure" Asp.net web API application: Asp.net web API module dependency.

This article describes how to add some content to this "pure" application. In fact, there have been many articles on ASP.net Web APIs, but they seldom talk about how to classify controllers. Why do we need to classify them? If a project is a little larger and the controller is a little larger, and all controllers are accessed through the URI "API/controllername", it will inevitably lead to confusion, your controller may have a duplicate name, or you may feel that the structural hierarchy is unclear.

Maybe you think of it now: area! Yes. Does Asp.net MVC provide the area function? With area, we can divide functions and organize them well. Unfortunately, area is really a MVC function, not a web API function. web API does not directly support area. The solution exists. Please refer to this article: Asp. net MVC 4 RC: Getting webapi and areas to play nicely, you can follow the methods it provides to solve this problem, but this time I plan to use my own method, because I created a pure web API application without webpage output, and I want a simpler structure. This is my web API:

I am afraid this example is not very close to reality, but it is easy to understand. The interface provided by the company portal I designed is divided into two parts: "Contact Us ", the second is "Product Introduction", and "Product Introduction" is divided into two categories: "Office Products" and "Game Products". For the sake of simplicity, all controllers are web API controllers created by default, with no more specific functions.

I will list all Uris and controllers into a table:

Controller name Namespace Uri
Advisecontroller Webapiroutedemo. controllers. contactus /Apix/contactus/advise
Productfeedbackcontroller Webapiroutedemo. controllers. contactus /Apix/contactus/productfeedback
Financialcontroller Webapiroutedemo. controllers. Products. Enterprise /Apixx/products/enterprise/Financial
Officecontroller Webapiroutedemo. controllers. Products. Enterprise /Apixx/products/enterprise/office
Puzcontroller Webapiroutedemo. controllers. Products. Game /Apixx/products/GAME/puz
Rpgcontroller Webapiroutedemo. controllers. Products. Game /Apixx/products/GAME/RPG
Rtscontroller Webapiroutedemo. controllers. Products. Game /Apixx/products/GAME/RTS
Allproductscontroller Webapiroutedemo. controllers. Products /Apix/products/allproducts
Aboutcontroller Webapiroutedemo. Controllers /API/about

The URI Prefixes "API", "apix", and "apixx" seem a little weird. I don't have a better way to design this URI route, we have to use this most stupid method to distinguish different URI routing rules. apixx indicates that area (main type) and category (small class) will be taken next, apix indicates that area will be taken next without category, while the API indicates that the following is the Controller directly, and there is no area or category. This is my path defined by the rule:

            config.Routes.MapHttpRoute("AreaCategoryApi", "apixx/{area}/{category}/{controller}/{id}",new {id = RouteParameter.Optional});            config.Routes.MapHttpRoute("AreaApi", "apix/{area}/{controller}/{id}", new {id = RouteParameter.Optional});            config.Routes.MapHttpRoute("DefaultApi", "api/{controller}/{id}", new {id = RouteParameter.Optional});

Then, how does the web API framework ultimately find the Controller it needs? It is actually based on the name. By default, but now, apart from the name and namespace, so you notice that the namespace I listed above exactly reflects the location of the controller and its functional level. To change the default controller selection behavior, we need to re-write a class to implement the ihttpcontrollerselector interface. The default class is "defaulthttpcontrollerselector". We can use it as the parent class:

    public class ClassifiedHttpControllerSelector : DefaultHttpControllerSelector    {        private const string AREA_ROUTE_VARIABLE_NAME = "area";        private const string CATEGORY_ROUTE_VARIABLE_NAME = "category";        private const string THE_FIX_CONTROLLER_FOLDER_NAME = "Controllers";        private readonly HttpConfiguration m_configuration;        private readonly Lazy<ConcurrentDictionary<string, Type>> m_apiControllerTypes;        public ClassifiedHttpControllerSelector(HttpConfiguration configuration) : base(configuration)        {            m_configuration = configuration;            m_apiControllerTypes = new Lazy<ConcurrentDictionary<string, Type>>(GetAllControllerTypes);        }        public override HttpControllerDescriptor SelectController(HttpRequestMessage request)        {            return GetApiController(request);        }        private static string GetRouteValueByName(HttpRequestMessage request, string strRouteName)        {            IHttpRouteData data = request.GetRouteData();            if (data.Values.ContainsKey(strRouteName))            {                return data.Values[strRouteName] as string;            }            return null;        }        private static ConcurrentDictionary<string, Type> GetAllControllerTypes()        {            Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();            Dictionary<string, Type> types = assemblies.SelectMany(a => a.GetTypes().Where(t => !t.IsAbstract && t.Name.EndsWith(ControllerSuffix, StringComparison.OrdinalIgnoreCase) && typeof (IHttpController).IsAssignableFrom(t))).ToDictionary(t => t.FullName, t => t);            return new ConcurrentDictionary<string, Type>(types);        }        private HttpControllerDescriptor GetApiController(HttpRequestMessage request)        {            string strAreaName = GetRouteValueByName(request, AREA_ROUTE_VARIABLE_NAME);            string strCategoryName = GetRouteValueByName(request, CATEGORY_ROUTE_VARIABLE_NAME);            string strControllerName = GetControllerName(request);            Type type;            try            {                type = GetControllerType(strAreaName, strCategoryName, strControllerName);            }            catch (Exception)            {                return null;            }            return new HttpControllerDescriptor(m_configuration, strControllerName, type);        }        private Type GetControllerType(string areaName, string categoryName, string controllerName)        {            IEnumerable<KeyValuePair<string, Type>> query = m_apiControllerTypes.Value.AsEnumerable();            string strControllerSearchingName;            if (string.IsNullOrEmpty(areaName))            {                strControllerSearchingName = THE_FIX_CONTROLLER_FOLDER_NAME + "." + controllerName;            }            else            {                if (string.IsNullOrEmpty(categoryName))                {                    strControllerSearchingName = THE_FIX_CONTROLLER_FOLDER_NAME + "." + areaName + "." + controllerName;                }                else                {                    strControllerSearchingName = THE_FIX_CONTROLLER_FOLDER_NAME + "." + areaName + "." + categoryName + "." + controllerName;                }            }            return query.Where(x => x.Key.IndexOf(strControllerSearchingName, StringComparison.OrdinalIgnoreCase) != -1).Select(x => x.Value).Single();        }    }

The above code is largely based on ASP. net MVC 4 RC: Getting webapi and areas to play nicely, whose role is based on Routing Parameters (the parameters include "area", "category", and "controller ") find the corresponding controller from the Assembly.

In this way, we have completed the classification of the controller. You can also adjust the routing rules to design better, but don't forget to share it with me.

Final convention, with: complete code

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.