基于WebActivator的改进版本KudyStudio.Web.Activating讲解与下载

  前天刚发过文章介绍了KudyStudio.Web.Activating,今天再次作了修改,并提供源码给大家。

  KudyStudio.Web.Activating下提供了两个属性分别是ActivationAttribute、ActivationMethodAttribute,利用它们可以灵活地随时在你的程序集中注册一个或多个Appilcation_Start()前/后触发和Appilcation_End()前触发的处理事件。 KudyStudio文章目录

 

   下载源码KudyStudio.Web.Activating.rar(.Net4.0)

 

 

  可触发的函数目标定义如下:

/// <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,这个属性允许你以静态方法方式来向程序集注册一个或多个触发函数,并指定触发函数的目标执行顺序,它的定义如下:

 

 

  有了ActivationMethodAttribute属性其实可以满足基本需求了,但是ActivationAttribute属性能让你的代码组织更清晰,怎么说?因为注册触发函数时不需要传入函数名称,而且方便每个程式元件建立自己的实现类(实现IPreApplicationStart、IPostApplicationStart、IPreApplicationEnd中的一个或多个接口)而不和其它程式元件的注册事务混在一起。ActivationAttribute属性这个允许你以实现接口方式来向程序集注册一个或多个触发函数,并指定触发函数的执行顺序,定义如下:

 

   重点的实现就是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触发函数也正常的按顺序执行了。

 

  文章到此结束了,如果本文对你有帮助请点击推荐表示支持,谢谢,转载时请务必写明出处。

posted @   Kudy  阅读(2975)  评论(16编辑  收藏  举报
编辑推荐:
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
阅读排行:
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 地球OL攻略 —— 某应届生求职总结
· 提示词工程——AI应用必不可少的技术
· Open-Sora 2.0 重磅开源!
· 周边上新:园子的第一款马克杯温暖上架
点击右上角即可分享
微信分享提示