ActivationMethodAttribute,利用它们可以灵活地随时在你的程序集中注册一个或多个Appilcation_Start()前/后触发和Appilcation_End()前触发的处理事件。
可触发的函数目标定义如下:
/// <summary> /// Specifies the targets to use for invoking activation methods. /// </summary> [Serializable] public enum ActivationMethodTarget
{ /// <summary>
/// Provides expanded support for ASP.NET application pre-start.
/// </summary>
PreApplicationStart = 0x0,
/// <summary>
/// Provides expanded support for ASP.NET application post-start.
/// </summary>
PostApplicationStart,
/// <summary>
/// Provides expanded support for before ASP.NET application shutdown.
/// </summary>
PreApplicationEnd
} |
先介绍ActivationMethodAttribute,这个属性允许你以静态方法方式来向程序集注册一个或多个触发函数,并指定触发函数的目标与执行顺序,它的定义如下:
/// <summary> /// Provides expanded support for application activation. /// </summary> [AttributeUsage(AttributeTargets.Assembly, AllowMultiple= true )]
public sealed class ActivationMethodAttribute : OrderableAttribute
{ #region Constructors
/// <summary>
/// Initializes a new instance of the ActivationMethodAttribute class.
/// </summary>
/// <param name="type">An object that describes the type of the activation method.</param>
/// <param name="methodName">An empty parameter signature that has no return value.</param>
public ActivationMethodAttribute(Type type, string methodName)
: this (type, methodName, ActivationMethodTarget.PreApplicationStart)
{
}
/// <summary>
/// Initializes a new instance of the ActivationMethodAttribute class.
/// </summary>
/// <param name="type">An object that describes the type of the activation method.</param>
/// <param name="methodName">An empty parameter signature that has no return value.</param>
/// <param name="methodTarget">The method target for the associated activation method</param>
public ActivationMethodAttribute(Type type, string methodName, ActivationMethodTarget methodTarget)
{
type.ThrowsIfNull( "type" );
methodName.ThrowsIfNullOrEmpty( "methodName" );
if (!Enum.IsDefined( typeof (ActivationMethodTarget), methodTarget))
{
throw new ArgumentException( "The methodTarget is undefined." );
}
this .Type = type;
this .MethodName = methodName;
this .MethodTarget = methodTarget;
}
#endregion
#region Properties
/// <summary>
/// Gets the type that is returned by the associated activation method.
/// </summary>
public Type Type
{
get ;
private set ;
}
/// <summary>
/// Gets the associated activation method.
/// </summary>
public string MethodName
{
get ;
private set ;
}
/// <summary>
/// Gets or sets the method target for the associated activation method.
/// </summary>
public ActivationMethodTarget MethodTarget
{
get ;
set ;
}
#endregion
} |
有了ActivationMethodAttribute属性其实可以满足基本需求了,但是ActivationAttribute属性能让你的代码组织更清晰,怎么说?因为注册触发函数时不需要传入函数名称,而且方便每个程式元件建立自己的实现类(实现IPreApplicationStart、IPostApplicationStart、IPreApplicationEnd中的一个或多个接口)而不和其它程式元件的注册事务混在一起。ActivationAttribute属性这个允许你以实现接口方式来向程序集注册一个或多个触发函数,并指定触发函数的执行顺序,定义如下:
/// <summary> /// Provides expanded support for application activation(s). /// </summary> [AttributeUsage(AttributeTargets.Assembly, AllowMultiple= true )]
public sealed class ActivationAttribute : OrderableAttribute
{ #region Constructors
/// <summary>
/// Initializes a new instance of the ActivationAttribute class.
/// </summary>
/// <param name="type">
/// An object that implements any activation interface (<see cref="IPreApplicationStart"/>,
/// <see cref="IPostApplicationStart"/>, <see cref="IPreApplicationEnd"/>).
/// </param>
public ActivationAttribute(Type type)
{
type.ThrowsIfNull( "type" );
this .Type = type;
}
#endregion
#region Properties
/// <summary>
/// Gets the type that implements any activation interface.
/// </summary>
public Type Type
{
get ;
private set ;
}
#endregion
} |
重点的实现就是ActivationManager类的InvokeActivationMethods方法,代码如下:
private static void InvokeActivationMethods(ActivationMethodTarget target)
{ List<OrderableAttribute> allAttributes = new List<OrderableAttribute>();
// get all attributes
foreach (Assembly assembly in AppAssemblies.Concat(GetCodeAssemblies(target)))
{
allAttributes.AddRange(GetAttributes<ActivationMethodAttribute>(assembly).Cast<OrderableAttribute>());
allAttributes.AddRange(GetAttributes<ActivationAttribute>(assembly).Cast<OrderableAttribute>());
}
// handle all ordered attributes
foreach (OrderableAttribute attribute in allAttributes.OrderBy(attr => attr.Order))
{
// invokes static method activations
ActivationMethodAttribute methodAttribute = attribute as ActivationMethodAttribute;
if (methodAttribute != null && methodAttribute.MethodTarget == target)
{
MethodInfo method = methodAttribute.Type.GetMethod(methodAttribute.MethodName, StaticMethodBindingFlags);
if (method != null )
{
method.Invoke( null , null );
continue ; // continue next target
}
// method not found
throw new ApplicationException( string .Format( "The type {0} doesn't have a static method named {1}." , methodAttribute.Type, methodAttribute.MethodName));
}
// try next case:
// invokes activations of activation classes that implements any activation interface
ActivationAttribute classAttribute = attribute as ActivationAttribute;
if (classAttribute != null )
{
Type type = classAttribute.Type;
object activation = null ;
if (IsValidActivationType(type))
{
try
{
activation = Activator.CreateInstance(type);
}
catch (Exception ex)
{
throw new ApplicationException( string .Format( "Fail to create instance of type {0}." , methodAttribute.Type), ex);
}
}
else
{
// invalid activation class
throw new ApplicationException( string .Format( "The type {0} is not a valid activation class." , type.FullName));
}
if (activation != null )
{
if (target == ActivationMethodTarget.PreApplicationStart && (activation is IPreApplicationStart))
{
(activation as IPreApplicationStart).PreApplicationStart();
}
else if (target == ActivationMethodTarget.PostApplicationStart && (activation is IPostApplicationStart))
{
(activation as IPostApplicationStart).PostApplicationStart();
}
else if (target == ActivationMethodTarget.PreApplicationEnd && (activation is IPreApplicationEnd))
{
(activation as IPreApplicationEnd).PreApplicationEnd();
}
}
}
}
} |
.NET 4.0版本新增了一个 PreApplicationStartMethodAttribute 类只提供了一个开始的前触发支持,那怎么实现开始后触发和结束前触发呢?.Net4.0中提供了一个叫DynamicModuleUtility的类(位于Microsoft.Web.Infrastructure.dll程序集),里面只有一个方法RegisterModule(Type moduleType),利用它可以动态的添加HttpModule。WebActivator的作者就是巧妙的利用了动态注册HttpModule。在第一个处理触发事件的HttpModule初始化时触发PostApplicationStart,最后一个HttpModule销毁时触发PreApplicationEnd,核心原理就这么两点,比较简单,KudyStudio.Web.Activating里的源码并没有作优化,因为在应用程序周期只触发一次各个事件,没必要刻意的去代码加载速度什么的。另外提醒一下,WebActivator1.5版本里的触发顺序只在每个独立程序集有效(不知道是不是作者故意的),KudyStudio.Web.Activating的触发顺序是在整个应用程序的全部程序集都有效的(有效是指排序的范围),感兴趣的朋友请下载源码分析。
下载KudyStudio.Web.Activating.rar(.Net4.0)
在此再附上测试实例说明吧,ActivatingWeb网站项目中ActivatingTest.cs里写了触发函数的实现与注册,Global.asax是用于辅助测试的。运行网站的结果如下:
所有触发函数都按指定的顺序执行了,打开Web.config后点击保存,查看网站根目录下的ActivatingTest.txt内容为:
可以看到PreApplicationEnd触发函数也正常的按顺序执行了。
文章到此结束了,如果本文对你有帮助请点击推荐表示支持,谢谢,转载时请务必写明出处。
关于KudyStudio企业类库:本人为公司写的一个功能性类库(主要Web方向,轻量的,Winform程序也可以使用),它主要包括网站开发中的常用功能如常用集合类、数据缓存(包括Memcached和Membase客户端)、数据库操作、自己定义配置管理、日志处理、数据压缩、数据加密、方法扩展、关键字过虑、简单图片处理、地址重写、网站表示层框架、各种功能性小框架等等等,远不止这些,目前还在整理完善中,大约在2012年底在公司项目完善时稳定初版本应该就会发布了,它可以免费提供给大家个人或商业使用,但此项目目前是不打算开源的,谢绝索要源码,如果会开源自然就开源的。(请不要向本人发出攻击,相信没多少公司会把自己内部的产品源码发出去,能免费提供使用就很不错了,不是吗?)在最近一年内的开发整理中发布的关于KudyStudio的文章会或多或少提供一些源码分析,如果你想关注和使用此类库,请关注本博客。
工作室网站:www.kudystudio.com (未完成)