自定义IHttpHandlerFactory使用Unity对ASP.NET Webform页面进行依赖注入

 简介:使用HttpHandlerFactory对ASP.NET Webform的页面进行依赖注入,不仅仅是Unity,使用同样的思路也可以用Spring.NET

 

背景

在日常的开发中,特别是使用了多层结构的程序,在视图层的页面逻辑中时常会用到业务逻辑的对象,此时就有可能产生如下的代码

Unity&WebForm(1): 自定义IHttpHandlerFactory使用Unity对ASP.NET Webform页面进行依赖注入 public   partial   class  Default : System.Web.UI.Page
Unity&WebForm(1): 自定义IHttpHandlerFactory使用Unity对ASP.NET Webform页面进行依赖注入 {
Unity&WebForm(1): 自定义IHttpHandlerFactory使用Unity对ASP.NET Webform页面进行依赖注入    public IUser UserService
Unity&WebForm(1): 自定义IHttpHandlerFactory使用Unity对ASP.NET Webform页面进行依赖注入    {
Unity&WebForm(1): 自定义IHttpHandlerFactory使用Unity对ASP.NET Webform页面进行依赖注入        get;
Unity&WebForm(1): 自定义IHttpHandlerFactory使用Unity对ASP.NET Webform页面进行依赖注入        set;
Unity&WebForm(1): 自定义IHttpHandlerFactory使用Unity对ASP.NET Webform页面进行依赖注入    }

Unity&WebForm(1): 自定义IHttpHandlerFactory使用Unity对ASP.NET Webform页面进行依赖注入
Unity&WebForm(1): 自定义IHttpHandlerFactory使用Unity对ASP.NET Webform页面进行依赖注入    protected void Page_Load(object sender, EventArgs e)
Unity&WebForm(1): 自定义IHttpHandlerFactory使用Unity对ASP.NET Webform页面进行依赖注入    {
Unity&WebForm(1): 自定义IHttpHandlerFactory使用Unity对ASP.NET Webform页面进行依赖注入       
Unity&WebForm(1): 自定义IHttpHandlerFactory使用Unity对ASP.NET Webform页面进行依赖注入    }

Unity&WebForm(1): 自定义IHttpHandlerFactory使用Unity对ASP.NET Webform页面进行依赖注入}


此代码的问题在于,没有一个适当的地方初始化User对象,虽然可以借助工厂在Page_Load中加入初始化的逻辑,但是每一个页面都需要手动地初始化对象显然并不合适
而在MVC模式下,在Controller中经常会用到依赖注入的方式将User对象注入,例如JAVA中的Structs和Webworks都可以配合Spring进行注入,而新出的ASP.NET MVC Framework也有相关的配合Unity进行依赖注入的技术文章
但是对于Webform,因为整个页面的执行相对封闭,没有很好的扩展环节,使注入显得不是那么容易
此文将使用自定义的IHttpHandlerFactory,在页面的生成时期使用Unity进行依赖注入,在不影响系统的运行的前提下,无侵入性地完成此项工作

 

原理

在ASP.NET的执行周期中,在经过了HttpModule之后,会由HttpHandlerFactory生成具体的Handler,随后进行Handler的生命周期,因此如果需要对同是HttpHandler的Page进行依赖注入,就需要使用HttpHandlerFactory的GetHandler方法生成完成注入后的Page对象
原本ASP.NET中用于生成Page对象的HttpHandlerFactory叫PageHandlerFactory,此类的构造函数被隐藏了,因此需要使用Activator来生成对象,再从PageHandlerFactory的对象中生成原有的Page对象
在获取了Page对象之后,我们就可以使用Unity为其进行依赖注入,所幸的是Unity提供了BuildUp方法来对已经生成的对象进行注入
当然其间还是有不少需要注意的问题,在实现环节中一一说明

 

using System;
using System.Web;
using System.Web.UI;
using System.Configuration;
using Microsoft.Practices.Unity;
using Microsoft.Practices.Unity.Configuration;

namespace MyDataUtilyTest
{
    //此类实现原理

    /// <summary>
    /// 在ASP.NET的执行周期中,在经过了HttpModule之后,会由HttpHandlerFactory生成具体的Handler,
    /// 随后进行Handler的生命周期,因此如果需要对同是HttpHandler的Page进行依赖注入,
    /// 就需要使用HttpHandlerFactory的GetHandler方法生成完成注入后的Page对象
    /// 原本ASP.NET中用于生成Page对象的HttpHandlerFactory叫PageHandlerFactory,
    /// 此类的构造函数被隐藏了,因此需要使用Activator来生成对象,
    /// 再从PageHandlerFactory的对象中生成原有的Page对象
    /// 在获取了Page对象之后,我们就可以使用Unity为其进行依赖注入,
    /// 所幸的是Unity提供了BuildUp方法来对已经生成的对象进行注入
    /// </summary>
   
    public class UnityHttpHandlerFactory : IHttpHandlerFactory
    {
        //需要初始化一个UnityContainer,这里使用静态变量
        private static readonly IUnityContainer unityContainer;

        static UnityHttpHandlerFactory()
        {
            //初始化UnityContainer
            string containerName = ConfigurationManager.AppSettings["HttpHandlerUnityContainerName"];
            if (String.IsNullOrEmpty(containerName))
            {
                containerName = "HttpHandlerContainer";
            }

            unityContainer = new UnityContainer();
            UnityConfigurationSection section = (UnityConfigurationSection)ConfigurationManager.GetSection("unity");
            section.Containers[containerName].Configure(unityContainer);
        }

        public IHttpHandler GetHandler(HttpContext context, string requestType, string url, string pathTranslated)
        {
            IHttpHandlerFactory pageFactory = CreatePageFactory();
            IHttpHandler pageHandle = pageFactory.GetHandler(context,requestType,url,pathTranslated);
            pageHandle = Build(pageHandle);
            return pageHandle;
        }

        public void ReleaseHandler(IHttpHandler handler)
        {
            IHttpHandlerFactory pageFactory = CreatePageFactory();
            pageFactory.ReleaseHandler(handler);
        }

        /// <summary>
        /// 在GetHandler方法中,取得具体的Page对象后,使用了一个Build方法对其进行包装,
        /// </summary>
        /// <param name="httpHandler"></param>
        /// <returns></returns>
        private static IHttpHandler Build(IHttpHandler httpHandler)
        {
            //Build方法使用UnityContainer的BuildUp方法对Page对象进行注入,这里有2点需要注意
            //注意1.因为并不能保证每一个Page都在UnityContainer中有注册,所以此处的BuildUp并不保证成功,
            //需要用catch捕获BuildUp过程中抛出的异常,如果BuildUp失败,则返回原有的实例即可
            //注意2.在ASP.NET运行期间,PageHandlerFactory生成的是编程时相应Page的子类,所以在
            //UnityContainer中寻找注册的类型的时候,需要使用page.GetType().BaseType才可
            //

            try
            {
                return unityContainer.BuildUp(httpHandler.GetType().BaseType,httpHandler) as IHttpHandler;
            }
            catch
            {
                return httpHandler;
            }
        }

        private static IHttpHandlerFactory CreatePageFactory()
        {
            //简单地使用Activator构造一个PageHandlerFactory的实例
            //在这里CreateInstance方法给了两个参数,第二个参数是这样子的,
            //如果公共或非公共默认构造函数可以匹配,则为 true;如果只有公共默认构造函数可以匹配,则为 false。


            IHttpHandlerFactory pageFactory =
                Activator.CreateInstance(typeof(PageHandlerFactory), true) as IHttpHandlerFactory;
            if (pageFactory == null)
            {
                throw new ApplicationException("Unable to initialize 'PageHandlerFactory'");
            }

            return pageFactory;
        }

       

    }
   
}

 

 

为了保持灵活性,使用了配置文件的方式读取UnityContainer,默认配置在web.config中

 

最后的工作当然是将此HttpHandlerFactory加入运行环境,在web.config中system.web配置组下的httpHandlers段加入以下2行即可

Unity&WebForm(1): 自定义IHttpHandlerFactory使用Unity对ASP.NET Webform页面进行依赖注入 < remove  verb ="*"  path ="*.aspx" />
Unity&WebForm(1): 自定义IHttpHandlerFactory使用Unity对ASP.NET Webform页面进行依赖注入 < add  verb ="*"  path ="*.aspx"  type ="Cst.Core.Web.Factory.UnityHttpHandlerFactory, Cst.Core.Web" />

这2行将原有的默认HttpHandlerFactory(即PageHandlerFactory)取消,代替以新的UnityHttpHandlerFactory

 

问题

1.因为在Unity中注册的页面其实只是用来作为BuildUp的参考,所以其生命周期管理是Transient好还是Singleton好依旧是个问题,有待更详细的测试
2.Unity只提供对public的属性的注入,需要对protected属性注入还要自己写扩展
3.只能用属性注入,因为Page的构造是由PageHandlerFactory完成的,Unity无力拦截构造函数的注入

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值