背景

在日常的开发中,特别是使用了多层结构的程序,在视图层的页面逻辑中时常会用到业务逻辑的对象,此时就有可能产生如下的代码
自定义IHttpHandlerFactory使用Unity对ASP.NET Webform页面进行依赖注入 (转)public partial class Default : System.Web.UI.Page
}

此代码的问题在于,没有一个适当的地方初始化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方法来对已经生成的对象进行注入
当然其间还是有不少需要注意的问题,在实现环节中一一说明

实现

首先自定义一个HttpHandlerFactory,在此称之为UnityHttpHandlerFactory,其GetHandler方法和ReleaseHandler方法均调用PageHandlerFactory的相应方法,具体如下
自定义IHttpHandlerFactory使用Unity对ASP.NET Webform页面进行依赖注入 (转)public IHttpHandler GetHandler(HttpContext context, string requestType, string url, string pathTranslated)
}

其中的CreatePageFactory方法如下,简单地使用Activator构造一个PageHandlerFactory的实例
自定义IHttpHandlerFactory使用Unity对ASP.NET Webform页面进行依赖注入 (转)private static IHttpHandlerFactory CreatePageFactory()
}

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


当然在此之前,需要初始化一个UnityContainer,这里使用静态变量,代码如下
自定义IHttpHandlerFactory使用Unity对ASP.NET Webform页面进行依赖注入 (转)private static readonly IUnityContainer unityContainer;
自定义IHttpHandlerFactory使用Unity对ASP.NET Webform页面进行依赖注入 (转)
自定义IHttpHandlerFactory使用Unity对ASP.NET Webform页面进行依赖注入 (转)
static UnityHttpHandlerFactory()
}
为了保持灵活性,使用了配置文件的方式读取UnityContainer,默认配置在web.config中,窗口名为HttpHandlerContainer,本人示例中的配置文件如下
>

最后的工作当然是将此HttpHandlerFactory加入运行环境,在web.config中system.web配置组下的httpHandlers段加入以下2行即可
自定义IHttpHandlerFactory使用Unity对ASP.NET Webform页面进行依赖注入 (转)<remove verb="*" path="*.aspx"/>
自定义IHttpHandlerFactory使用Unity对ASP.NET Webform页面进行依赖注入 (转)
<add verb="*" path="*.aspx" type="Cst.Core.Web.Factory.UnityHttpHandlerFactory, Cst.Core.Web"/>
这2行将原有的默认HttpHandlerFactory(即PageHandlerFactory)取消,代替以新的UnityHttpHandlerFactory

为了演示具体的效果,在Default的Page_Load方法中加入代码,使方法最终如下
自定义IHttpHandlerFactory使用Unity对ASP.NET Webform页面进行依赖注入 (转)protected void Page_Load(object sender, EventArgs e)
}


结果当然是如预期地显示出了"注入成功"字样,也就不放图了~

问题

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

 

总结

本文提供了一种思路,使用HttpHandlerFactory对ASP.NET Webform的页面进行依赖注入,不仅仅是Unity,使用同样的思路也可以用Spring.NET或者Castle进行依赖注入,同样,也可以配合使用PIAB完成更多的功能

最后题外话:哪位老师有Unity的扩展方面的相关教程的请告诉我一下,特别是Inject方面的扩展(比如通过从Session或者QueryString取对象),万分感谢

相关文章:

  • 2021-06-25
  • 2021-10-09
  • 2021-12-07
  • 2022-12-23
  • 2021-08-20
  • 2022-12-23
  • 2022-12-23
猜你喜欢
  • 2021-11-22
  • 2021-05-18
  • 2022-01-16
  • 2022-01-17
  • 2022-12-23
相关资源
相似解决方案