IoC显然是它得到的第一件事情,但这给我留下了服务定位模式和不好的味道,以及是否可以做得更好.
我已经在线聊天的各位告诉我,我可以使用一个HttpModule进行属性注入,该模式可以扫描一个用类别为Inject属性装饰的属性的页面类,但这听起来像是一个Reflection(缓存,但仍然)每一个请求不吸引人
所以我正在看其他的选择,并发现了System.Web.IHttpHandlerFactory,这显然是从v2以来的框架.可以在httpHandlers web.config部分中删除默认的* .aspx处理程序并将其替换为使用自定义实现的处理程序.
所以,我谈过的人并不愚蠢;我以为我会问这里.是否有任何问题,用基于IoC的实现替换Webforms PageHandlerFactory??
看起来它有一个CreateHandler和ReleaseHandler方法,所以生活方式相关的内存从容器泄漏,保留对创建的组件的引用不应该是一个问题…
解决方法
public partial class _Default : System.Web.UI.Page { private IUserService service; protected _Default() { } public _Default(IUserService service) { this.service = service; } }
这允许您创建一个自定义的PageHandlerFactory并在构造函数中注入依赖关系.
所以这是有效的,但有一个抓住.您定义的_Default类不是ASP.NET使用的实际类. ASP.NET创建一个继承自_Default的新类.这个新类基于.aspx文件中的标记构建一个控制层次结构.这个班看起来有点像这样:
public class ASPGeneratedDefault : _Default { public ASPGeneratedDefault() : base() { } protected override void OnPreInit(object s,EventArgs e) { // Building up control hierarchy. } }
如您所见,ASP.NET中的自定义构造函数尚未被ASPGeneratedDefault覆盖.因此,没有办法让DI框架为我们创建这种类型.这样做的方法是让ASP.NET为我们创建此类型,并调用该现有实例上_Default基类的非默认构造函数.因为这个实例已经存在,所以我们必须用反射来做到这一点,而当以部分信任运行时,这将失败.
此外,这适用于页面类,但不适用于页面上的用户控件. ASP.NET的代码生成器在控制层次结构建立过程中,使用它们的默认构造函数来新闻这些控件.当您希望此功能适用于它们时,您需要使用自定义的PageHandlerFactory来挂接这些控件的PreInit事件,因为在构建页面类的时候,相关的控件和用户控件尚未创建.然而,要在其上注册PreInit事件,您需要在页面类中找到这些控件,并且我们需要反映页面类.由于控件存储在非公共实例字段中,因此这不会在部分信任中起作用.
无论是否是您的应用程序无法以部分信任方式运行的问题取决于您,但由于.NET 4的安全模型已被大大简化,因此以部分信任方式运行Web应用程序非常容易,这是我的一些努力做
TLDR;因此,总而言之,可以这样做(参见例如this example),但由于ASP.NET Web窗体框架的限制,您需要完全信任地运行以使其正常工作.
UPDATE从.NET 4.0开始,Microsoft已经废除了ASP.NET的部分信任(见here).所以从这个角度来看,远离完全信任可能不是那么有用(反正你还需要).