上篇文章,我們分析如何動態注冊HttpModule的實現,本篇我們來分析一下通過上篇代碼原理實現的WebActivator類庫,WebActivator提供了3種功能,允許我們分別在HttpApplication初始化之前,之後以及ShutDown的時候分別執行指定的代碼,示例如下:
[assembly: WebActivator.PreApplicationStartMethod(typeof(A.InitClass1), "PreStart")] [assembly: WebActivator.PostApplicationStartMethod(typeof(A.InitClass1), "PostStart")] [assembly: WebActivator.ApplicationShutdownMethod(typeof(A.InitClass1), "ShutDown")]
另外還有一點和系統自帶的PreApplicationStartMethodAttribute不同的是,WebActivator的每種特性都可以使用多次,比如:
[assembly: WebActivator.PreApplicationStartMethod(typeof(A.InitClass1), "PreStart")] [assembly: WebActivator.PreApplicationStartMethod(typeof(A.InitClass2), "PreStart")] [assembly: WebActivator.PreApplicationStartMethod(typeof(A.InitClass3), "PreStart")]
因為它的源碼很少,所以今天我們就來全面分析一下WebActivator的實現原理,首先下載WebActivator的最新1.5源碼,源碼地址:https://bitbucket.org/davidebbo/webactivator/src
解壓代碼,我們可以看到WebActivator項目裡總共有6個重要的cs文件,以及一個packages.config文件(用於標記本項目引用了Microsoft.Web.Infrastructure.dll類庫),下面我們來分析一下每個文件的源碼。
3個XXXMethodAttribute屬性:
根據上面的用法,我們指導WebActivator提供了3個MethodAttribute,我們先來看看這3個文件都是如何實現的,查閱代碼發現3個類(PreApplicationStartMethodAttribute/ PostApplicationStartMethodAttribute/ ApplicationShutdownMethodAttribute)的內容都是一樣的,都是繼承於 BaseActivationMethodAttribute類,然後提供構造函數所需要的Type類型和方法名稱, 3個特性類都支持使用多次並且只能用於Assembly,代碼如下:
[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]
通用的基類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); } } }
通過代碼,我們首先可以看到,除了Type和MethodName以外,還多了一個Order屬性,用來標記多次使用同一個Attribute的時候的執行順序。然後提供了一個InvokeMethod方法,用來執行該類裡傳入當前Type類的MethodName靜態方法。
Assembly擴展方法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>(); } } }