The previous MVC series (7): a detailed explanation of the implementation principles of WebActivator

Source: Internet
Author: User

Article content

In the previous article, we analyzed how to dynamically register the implementation of HttpModule. In this article, we will analyze the WebActivator class library implemented through the previous Code principles. WebActivator provides three features, we can execute the specified code before HttpApplication initialization, after ShutDown, and during ShutDown respectively. The example is as follows:

[assembly: WebActivator.PreApplicationStartMethod(typeof(A.InitClass1), "PreStart")][assembly: WebActivator.PostApplicationStartMethod(typeof(A.InitClass1), "PostStart")][assembly: WebActivator.ApplicationShutdownMethod(typeof(A.InitClass1), "ShutDown")]

Another difference from the system's PreApplicationStartMethodAttribute is that each of the WebActivator features can be used multiple times, for example:

[assembly: WebActivator.PreApplicationStartMethod(typeof(A.InitClass1), "PreStart")][assembly: WebActivator.PreApplicationStartMethod(typeof(A.InitClass2), "PreStart")][assembly: WebActivator.PreApplicationStartMethod(typeof(A.InitClass3), "PreStart")]

Because of its source code is very few, so today we come to a comprehensive analysis of the implementation of WebActivator principle, first download the latest WebActivator 1.5 source code, Source Code address: https://bitbucket.org/davidebbo/webactivator/src

 

Decompress the code. We can see that the WebActivator project contains a total of 6 important cs files and a packages. config File (used to mark the reference of Microsoft. web. infrastructure. dll class library). Next we will analyze the source code of each file.

 

3 XXXMethodAttribute attributes:

According to the above usage, We have guided WebActivator to provide three methodattritri. Let's first look at how these three files are implemented and check the code to find three classes (PreApplicationStartMethodAttribute/PostApplicationStartMethodAttribute/ApplicationShutdownMethodAttribute) the content is the same. They all inherit from the BaseActivationMethodAttribute class, and then provide the Type and method name required by the constructor. The three feature classes can be used multiple times and can only be used for Assembly, the Code is as follows:

[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]
Common base class BaseActivationMethodAttribute:
using System;using System.Reflection;namespace WebActivator{    // Base class of all the activation attributes    [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]    public abstract class BaseActivationMethodAttribute : Attribute    {        private Type _type;        private string _methodName;        public BaseActivationMethodAttribute(Type type, string methodName)        {            _type = type;            _methodName = methodName;        }        public Type Type { get { return _type; } }        public string MethodName { get { return _methodName; } }        public int Order { get; set; }        public void InvokeMethod()        {            // Get the method            MethodInfo method = Type.GetMethod(                MethodName,                BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public);            if (method == null)            {                throw new ArgumentException(                    String.Format("The type {0} doesn't have a static method named {1}",                        Type, MethodName));            }            // Invoke it            method.Invoke(null, null);        }    }}

Through the code, we can see that in addition to Type and MethodName, there is also an Order Attribute to mark the execution sequence when the same Attribute is used multiple times. Then, an InvokeMethod method is provided to execute the MethodName static method for passing in the current Type class in this class.

 

Assembly Extension Method AssemblyExtensions:
using System.Collections.Generic;using System.Linq;using System.Reflection;namespace WebActivator{    static class AssemblyExtensions    {        // Return all the attributes of a given type from an assembly        public static IEnumerable<T> GetActivationAttributes<T>(this Assembly assembly) where T : BaseActivationMethodAttribute        {            return assembly.GetCustomAttributes(                typeof(T),                inherit: false).OfType<T>();        }    }}

This extension method is mainly used to obtain all attributes of the specified type (and does not include inherited classes) under an Assembly ), that is, to query the Attributes of the above three features (because each of them can be declared multiple times ).

 

Main management ActivationManager:

This class is divided into the following parts:

1. The Private Static function Assemblies. GetAssemblyFiles is mainly used to obtain all DLL assembly in the current application for other methods to traverse the corresponding feature declaration from this Assembly set.
// Load all the obtained Assembly private static IEnumerable <Assembly> Assemblies {get {if (_ assemblies = null) {// Cache the list of relevant assemblies, since we need it for both Pre and Post _ assemblies = new List <Assembly> (); foreach (var assemblyFile in GetAssemblyFiles ()) {try {// Ignore assemblies we can't load. they cocould be native, etc... _ assemblies. add (Assembly. loadFrom (assemblyFile);} catch {}} r Eturn _ assemblies; }}// obtain the private static IEnumerable <string> GetAssemblyFiles () {// When running under ASP. NET, find assemblies in the bin folder. // Outside of ASP. NET, use whatever folder WebActivator itself is in string directory = HostingEnvironment. isHosted? HttpRuntime. BinDirectory: Path. GetDirectoryName (typeof (ActivationManager). Assembly. Location); return Directory. GetFiles (directory, "*. dll ");}
2. Obtain the compiled assembly of code in all AppCode folders.
// Return all the App_Code assembliesprivate static IEnumerable<Assembly> AppCodeAssemblies{    get    {        // Return an empty list if we;re not hosted or there aren't any        if (!HostingEnvironment.IsHosted || !_hasInited || BuildManager.CodeAssemblies == null)        {            return Enumerable.Empty<Assembly>();        }        return BuildManager.CodeAssemblies.OfType<Assembly>();    }}
3. Execute the methods specified in the three features.
public static void RunPreStartMethods(){    RunActivationMethods<PreApplicationStartMethodAttribute>();}public static void RunPostStartMethods(){    RunActivationMethods<PostApplicationStartMethodAttribute>();}public static void RunShutdownMethods(){    RunActivationMethods<ApplicationShutdownMethodAttribute>();}// Call the relevant activation method from all assembliesprivate static void RunActivationMethods<T>() where T : BaseActivationMethodAttribute{    foreach (var assembly in Assemblies.Concat(AppCodeAssemblies))    {        foreach (BaseActivationMethodAttribute activationAttrib in assembly.GetActivationAttributes<T>().OrderBy(att => att.Order))        {            activationAttrib.InvokeMethod();        }    }}

From the code, we can see that the three feature execution methods call the same generic method RunActivationMethods <T>. In this method, it is mainly from all the Assembly sets, query the features of all tags by using the generic method (sorted by Order) and execute the methods specified in each feature declaration. In addition, from Assemblies. Concat (AppCodeAssemblies), we can find that all the Assembly also includes the Assembly compiled by code under the App_Code directory.

 

4. Custom HttpModule
class StartMethodCallingModule : IHttpModule{    private static object _lock = new object();    private static int _initializedModuleCount;    public void Init(HttpApplication context)    {        lock (_lock)        {            // Keep track of the number of modules initialized and            // make sure we only call the post start methods once per app domain            if (_initializedModuleCount++ == 0)            {                RunPostStartMethods();            }        }    }    public void Dispose()    {        lock (_lock)        {            // Call the shutdown methods when the last module is disposed            if (--_initializedModuleCount == 0)            {                RunShutdownMethods();            }        }    }}

This Module is mainly used to execute the PostStart method during Init, and to execute the Shutdown method only once during Dispose.

 

5. The most important entry Method
public static void Run(){    if (!_hasInited)    {        RunPreStartMethods();        // Register our module to handle any Post Start methods. But outside of ASP.NET, just run them now        if (HostingEnvironment.IsHosted)        {            Microsoft.Web.Infrastructure.DynamicModuleHelper.DynamicModuleUtility.RegisterModule(typeof(StartMethodCallingModule));        }        else        {            RunPostStartMethods();        }        _hasInited = true;    }}

The Run method seems easy to understand. First, execute the PreStart method and then judge whether the HostingEnvironment is successful. If it is successful, we dynamically register the custom HttpModule above, so that the Module can execute the PostStart method and the ShutDown method respectively during HttpApplication initialization and Dispose. If the Host fails, only the PostStart method is executed.

Note: The code implementation shows that in PreStart methods, the HttpContext object cannot be used for input and output, because the object has not been successfully created yet.

 

6. Who called the entry method Run ()

You don't need to talk about this. It must be the PreApplicationStartMethodAttribute feature that comes with. Net4.0. The Code is as follows:

[assembly: PreApplicationStartMethod(typeof(WebActivator.ActivationManager), "Run")]

You can place this code outside the namespace of any class file in the WebActivator project, but for the sake of uniformity, it is generally placed in the AssemblyInfo class file under the Properties Directory, which is what WebActivator does.

 

Summary: Well, this is the full source code of WebActivator. It is actually very simple to implement, right? When the project has similar requirements in the future, we should use this class library. In addition, NInject. MVC is also implemented based on this class library.

References:

Http://blogs.msdn.com/ B /davidebb/archive/2010/10/11/light-up-your-nupacks-with-startup-code-and-webactivator.aspx

Https://bitbucket.org/davidebbo/webactivator/src

Synchronization and recommendation

This article has been synchronized to the Directory Index: the previous MVC Series

The previous MVC series of articles, including original articles, translations, reposts, and other types of articles. If they are useful to you, we recommend that you support them to give uncle the motivation to write.

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.