How is the Controller created through ASP. NET Web API? We know that the AssembliesResolver used to parse the Assembly in Self Host mode by default ASP. NET Web API is a DefaultAssembliesResolver object, which only provides the Assembly already loaded by the current application domain. If we define HttpController as the program set where the non-Host Program is located (in fact, in Self Host mode, we basically choose to define the HttpController type in an independent project ), even if we place the components in the directory where the host program is running, the host Program does not take the initiative to load the Assembly at startup. Because the current application domain does not load these sets, the HttpController type resolution will fail, and the activation of HttpController will naturally fail. [This Article has been synchronized to How ASP. NET Web API Works?]
We can use a simple example to confirm this problem. In a solution, we define four projects, as shown in the right figure. Foo, Bar, and Baz are class library projects, and the corresponding HttpController type is defined in these three projects. Hosting is a console program that acts as the host and has reference to the above three projects. In project Foo, Bar, and Baz, we define three HttpController types inherited from ApiController: FooController, BarController, and BazController. As shown in the following code snippet, we define the unique Action method Get in the three HttpController types and let it return the AssemblyQualifiedName of the current HttpController type.
In the Hosting program as the Host, we use the following code to implement Web API-targeted boarding in the Self Host mode. We created an HttpSelfHostServer for the base address "http: // 127.0.0.1: 3721, before enabling the service, we have registered a URL template for "api/{controller}/{id}" routing.
After starting the Host Program, we try to call the Action method Get defined in FooController, BarController, and BazController in the browser. Unfortunately, we will Get the result 4-4. From the messages displayed in the browser, we know the crux of the problem: the HttpController name cannot be obtained according to route resolution.
We have analyzed the cause of the above problem: the default registered DefaultAssembliesResolver only provides the Assembly loaded by the current application domain. We can solve this problem through the custom AssembliesResolver. Our solution is to make the Assembly to be preloaded configurable. Specifically, we can use the configuration with the following structure to set the assembly to be preloaded.
Before creating a custom AssembliesResolver, we must first define the corresponding configuration section and configuration element type for this configuration. Related types (PreLoadedAssembliesSettings, AssemblyElementCollection, and AssemblyElement) are defined as follows. Since the configuration structure is simple, we will not detail them here.
Since our custom AssembliesResolver is an extension of the existing DefaultAssembliesResolver (although its Assembly provides a mechanism that is implemented only by a single code), we name the type ExtendedDefaultAssembliesResolver. As shown in the following code snippet, ExtendedDefaultAssembliesResolver inherits from DefaultAssembliesResolver. In the rewritten GetAssemblies method, we first analyze the preceding configuration and take the initiative to load the Assembly that has not been loaded, then, call the method with the same name as the base class to provide the final assembly.
We use the following code in the Hosting program as the host to register an ExtendedDefaultAssembliesResolver object to the ServicesContainer of the current HttpConfiguration.
After restarting the Host Program, enter the corresponding address in the browser again to access the Get Action method defined in FooController, BarController, and BazController, as shown in the output result, this is the result of the execution of the target Action method.