上篇文章,我們分析如何動態注冊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>();
}
}
}