Dynamic WEBAPI should be one of the most magic features in ABP. Developers do not need to define classes that inherit from Apicontroller, and simply reuse the classes in the application service to provide WEBAPI functionality, which should be considered the best interpretation of dry. As shown, a line of code automatically creates the corresponding dynamic WEBAPI for all types that implement the Iapplicationservice.
How is this magic function implemented?
This article is for you to uncover the appearance of its magic. You will find that the most critical code to achieve such a magic function is only four lines.
Consider one question: can we implement the ASP. NET WebApi if we don't inherit from the Apicontroller of ASP. WebApi?
Answer: No, you can't. The implementation of our own Httpcontroller from Apicontroller inheritance is the premise of implementing the ASP. NET Webapi.
Then the question comes again. When we used the ABP framework, we did not create any classes that inherit from Apicontroller. So where are the classes that inherit from Apicontroller and how do they relate to classes in Applicationservice?
Here's the answer: the ABP framework automatically creates "Httpcontroller" for classes in Applicationservice, which inherit from Apicontroller.
Based on the above analysis, there are three questions to be solved to implement WEBAPI: How to define a Httpcontroller? How are the rules for routing set? How do I activate and invoke an action in Httpcontroller? then answer each of them individually.
How do I define httpcontroller?
Applicationservice in ABP is not inherited from Apicontroller, or implements Ihttpcontroller interface. To solve the problem of Httpcontroller type missing, ABP first creates a dynamicapicontroller<t> for all applicationservice dynamically, This class inherits from Abpapicontroller, where T is an interface that inherits from Iapplicationservice.
But Dynamicapicontroller<t> is an empty class with no action on it. Such a Httpcontroller class is obviously useless. So how do you add the corresponding action to these dynamically generated dynamicapicontroller<t> objects based on the corresponding method in the T (Applicationservice interface)?
Seemingly complex problem, ABP solved in a clever way, the key is in the Abpwebapimodule 4 lines of code (below 59-62 lines). Here's a brief explanation of the ABP approach:
1. Create the Dynamicapicontroller<t> proxy class through Castle,
2. Add the Applicationservice interface dynamically for the proxy class (this is the T, which means that the proxy class implements the interface T so that the method defined in the interface T can be accessed through the proxy class).
3. Add interceptors for the proxy class at the same time.
This way , when the ABP obtains the dynamicapicontroller<t> instance through the castle, actually obtains is Dynamicapicontroller<t> 's proxy class (key). when calling the method defined in Applicationservice's interface through the Dynamicapicontroller<t> proxy class (must be called by reflection, Because the methods in interface T are not visible to dynamicapicontroller<t> instances. But it is actually visible, because you get a proxy class instance of dynamicapicontroller<t> inherited from the T interface, not the dynamicapicontroller<t> instance itself. ) will be intercepted by the interceptor. The interceptor then invokes the real Applicationservice object to execute the method (which is also critical here, as the proxy class is not implemented as long as the declaration of the method is made. So the interceptor needs to intercept its method call and route it to the real Applicationservice object. If you don't understand these four lines of code, read the following: Http://www.cnblogs.com/1zhk/p/5399548.html.
As an example:
Suppose there is a applicationservice interface that is ifooappication.
Line 59th,dynamicapicontroller<ifooappication> is register into the castle container.
Line 60th, create a proxy agent for dynamicapicontroller<ifooappication>, and add an interface ifooappication for the agent.
Line 61st, add interceptors for proxy proxies abpdynamicapicontrollerinterceptor<ifooappication>
How are the rules for routing set?
Hard-coded in ABP.WEB.API code by Abpwebapimodule's Initializeroutes method. It is clear that this route uses the * wildcard character, which means that all API/SERVICES/XXXX requests are valid and will go into the WEBAPI message pipeline.
How do I activate and invoke a specific generated Dynamicapicontroller<t> object based on Routedata?
ABP replaces the default Ihttpcontrollerselector object, Ihttpactionselector object, with a custom object by using the Abpwebapimodule Initializeaspnetservices method, The Ihttpcontrolleractivatore object. Developers who understand how the ASP. NET Webapi bottom-up works must be familiar with these three interfaces. If you do not know the students to do homework first, to understand the content of the text.
At this point, it probably explains how the dynamic webapi of the ABP works.
The following is an analysis of interfaces and objects related to dynamic Webapi. These interfaces and classes revolve around two central goals: to create a descriptor and selector (Descriptor,selector) for the dynamic controller to be used by the ASP. Webapi, and to build and save the type information for the dynamic controller.
First look at the Apicontroller and the configuration
Abpapicontroller: The WEBAPI controller in APICONTROLLER,ABP inherited from MVC is inherited directly or indirectly from Abpapicontroller. The second diagram shows the objects that the Abpapicontroller references to the functional modules in the core class library of the ABP.
Idynamicapicontroller: An empty interface used to identify that its implementation is a dynamically generated apicontroller.
Dynamicapicontroller<t>: Serves as the base class for all dynamically generated apicontroller.
iabpwebapimoduleconfiguration/abpwebapimoduleconfiguration : Encapsulates the Httpconfiguration property, Initializes the Globalconfiguration.configuration object. Because the ASP. NET Web API is obtained under WEB host through the configuration properties of the static type globalconfiguration of ASP. Httpconfiguration object used to configure the request processing pipeline. The dynamic webapi of ABP is essentially the ASP. NET Web API, so configuring Httpconfiguration is inevitable.
The interfaces and classes associated with controller activation and invocation are primarily the following. In fact, they are inherited from the default object used in ASP. Webapi and overloaded with methods to support dynamic Apicontroller discovery, activation, and invocation.
Dynamichttpcontrollerdescriptor : Inherited from the httpcontrollerdescriptor of the ASP. NET WebAPI system, with ASP. NET WebAPI A ifilter array is more than the default in Httpcontrollerdescriptor. The reason for this is simple because the Apicontroller in the ABP is dynamically generated and is not labeled with the filter attribute. So the ABP adds filter to the dynamic Apicontroller in this way.
Dynamichttpactiondescriptor : Inherited from the reflectedhttpactiondescriptor of the ASP. NET WebAPI system, with ASP. NET WebAPI A ifilter array is more than the default in Httpactiondescriptor. The reason for doing this is consistent with the above
Abphttpcontrollerselector : Inherited from the defaulthttpcontrollerselector of the ASP. WEBAPI System. By overriding Selectcontroller to return httpcontrollerdescriptor, this is the key to ABP's ability to dynamically create Apicontroller. The Ihttpcontrollerselector object in ASP. WebAPI is responsible for returning httpcontrollerdescriptor based on Httproutedata. Information such as the type of controller is encapsulated in the httpcontrollerdescriptor. Here ABP by inheriting Defaulthttpcontrollerselector, and override the Selectcontroller method to create a Httpcontrollerdescriptor object based on the data in Httproutedata and return
abpapicontrolleractivator: The Ihttpcontrolleractivator interface is implemented, and a specific controller is generated according to Controllertype. Because the ABP system uses the castle framework to manage objects. It is therefore necessary to implement your own ihttpcontrolleractivator to replace the default implementations of the ASP.
Abpapicontrolleractionselector : Inherits from the Apicontrolleractionselector of the ASP. WebAPI. Returns an instance of the Httpactiondescriptor derived class Dynamichttpactiondescriptor by overriding SelectAction. This is the key to the ABP's action method to perform dynamically created Apicontroller. Abpapicontrolleractionselector By calling Dynamicapiservicenamehelper's static method (passed in to the servicenamewithaction in Routedata) to get the action
dynamicapiservicenamehelper: Static class that provides four static methods. Two methods are used to verify servicename compliance, and two methods are used to get the name of the service and action in ServiceName.
abpdynamicapicontrollerinterceptor<t> : Realized the iinterceptor of Castle. As a dynamically generated dynamicapicontroller<t> interceptor, it intercepts all calls to the action and then invokes the method of the underlying real Iapplicationservice object through reflection.
In the traditional ASP. NET WEBAPI application, the system will match the type information of the controller according to the routing information, by reflecting to the Assembly. In the ABP, the type information of the controller is added directly to a dictionary collection when it is initialized. This is what the code in the first picture of this article did. The interfaces and classes involved in completing this function module are mainly the following.
As shown in the code, the data for building dynamichttpcontrollerdescriptor originates from a Dynamicapicontrollerinfo object. So when did the Dynamicapicontrollerinfo object build? is the type and interface involved in the ABP's Dynamicapicontrollerinfo object for building Applicationservice.
dynamicapicontrollerinfo: The ABP is used to encapsulate the Apicontroller information, showing all its properties. One of the most critical attributes is Apicontrollertype. is actually a dynamicapicontroller<t> type, where T is the type of the specific Applicationservice interface.
dynamicapiactioninfo: Information for encapsulating the action of dynamically generated Apicontroller: Actionname,filters, Methondinfo, and Httpverb. The dynamicapicontrollerinfo encapsulates a Dynamicapiactioninfo Dictionary object that represents the list of actions that the controller can support.
Dynamicapicontrollermanager: Provides a dictionary container to manage all Dynamicapicontrollerinfo objects. There are three methods: The Register method is used to add dynamicapicontrollerinfo to the dictionary container, and the other two methods are used to return dynamicapicontrollerinfo.
Dynamicapicontrollerbuilder: Provides two methods, one for<t> method through Apicontrollerbuilder for one application The service class creates dynamicapicontrollerinfo. Another forall<t> method uses Batchapicontrollerbuilder for a class of application service classes (this class of application The service will have a common interface) to create the Dynamicapicontrollerinfo.
iapicontrollerbuilder<t>/ Apicontrollerbuilder<t>: It encapsulates a Dictionary object idictionary<string, apicontrolleractionbuilder<t> > The Apicontrolleractionbuilder object that corresponds to each method that holds T. Finally, the complete Dynamicapicontrollerinfo object is generated by calling the build () method. Notice here the code of Iapicontrollerbuilder, he is support chain programming, can be Withfilters method to this application Service API Controller add filter
ibatchapicontrollerbuilder<t>/ batchapicontrollerbuilder<t> : Batch generation of Dynamicapicontrollerinfo for interfaces in assembly that conform to the naming convention. It continues by Apicontrollerbuilder to create dynamicapicontrollerinfo for each application service interface one at a.
For example, in the process of building dynamicapicontrollerinfo, Apicontrollerbuilder The Apicontrolleractionbuilder object needs to be called to build the dynamicapiactioninfo that the dynamicapicontrollerinfo contains.
dynamicapicontrolleractionhelper: Static class, which is used to get all the methods of a type except for the property, except for the native method of object. Applicationservice, except for the list.
dynamicapiverbhelper: Returns httpverb by convention according to the method name.
iapicontrolleractionbuilder/apicontrolleractionbuilder: Builder for building Dynamicapiactioninfo objects. Here's a note: for example, if the MethodName of an action starts with a GET, the default ABP labels its httpverb as get, but with one exception, if the method's arguments are not of type primitive and are not nullable, The ABP will mark its httpverb as post.
Abiapiexplorer: Inherits from the Apiexplorer class, implements the Iapiexplorer interface. Its Apidescriptions property includes both the Webapi (39-44 rows) you wrote yourself and the Webapi (47-) dynamically generated by the ABP.
The ABP iterates through the dynamiccontrollerinfo in the Dynamicapicontrollermanager and then iterates through the Dynamiccontrollerinfo Dynamicapiactioninfo, Build Apidescription instances for them individually.
Back to ABP source Analysis series Articles Directory
ABP Source Code Analysis 35: Principle Analysis of dynamic WEBAPI in ABP