当PageHandlerFactory和IHttpHandlerFactory存在时,为什么每个人都说ASP.NET webforms中的依赖注入很难?

Pet*_*nce 16 asp.net dependency-injection webforms inversion-of-control

所以我有一个遗留的webforms网站,正在努力使其更容易维护.把它拿走并重写它不是一种选择.

IoC显然是它最先得到的东西之一,但是这给我留下了服务定位器模式和糟糕的味道,并且想知道它是否可以做得更好.

我在网上聊过的各种人告诉我,我可以使用HttpModule进行属性注入,该HttpModule扫描一个Page类,用于使用Inject属性或类似物修饰的属性,但这听起来像一个Reflection命中(缓存,但仍然)在每个请求.不吸引人.

所以我正在寻找其他选项,并遇到了System.Web.IHttpHandlerFactory,它自v2以来一直在框架中.可以在httpHandlers web.config部分中删除默认的*.aspx处理程序并将其替换为使用自定义实现的处理程序.

所以,我与之交谈的人并不愚蠢; 我以为我会在这里问. 使用基于IoC的实现替换webforms PageHandlerFactory是否有任何问题?

看起来它同时具有CreateHandler和ReleaseHandler方法,因此从容器中保留对生成组件的引用的生活方式相关内存泄漏应该不是问题...

Ste*_*ven 28

由于ASP.NET的设计方式,Page类需要有一个默认的构造函数.当你想使用构造函数注入时,有一种解决方法.您可以使默认构造函数受到保护,并添加一个公共构造函数,该构造函数接受依赖项,如下所示:

public partial class _Default : System.Web.UI.Page
{
    private IUserService service;

    protected _Default()
    {
    }

    public _Default(IUserService service)
    {
        this.service = service;
    }
}
Run Code Online (Sandbox Code Playgroud)

这允许您创建自定义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.
     }
}
Run Code Online (Sandbox Code Playgroud)

如您所见,自定义构造函数尚未在ASPGeneratedDefault ASP.NET中被覆盖.因此,没有办法让DI框架为我们创建这种类型.解决这个问题的方法是让ASP.NET为我们创建这种类型,并_Default在该现有实例上调用基类的非默认构造函数.因为这个实例已经存在,所以我们必须使用反射执行此操作,这在部分信任中运行时将失败.

除此之外,这适用于页面类,但不适用于页面上的用户控件.在控制层次结构构建过程中,ASP.NET的代码生成器使用其默认构造函数来新闻这些控件.如果希望这对它们起作用,则需要使用自定义PageHandlerFactory来挂钩PreInit这些控件的事件,因为在构造页面类的过程中,尚未创建相关的控件和用户控件.但是,要PreInit在它们上注册事件,您需要在页面类中找到这些控件,我们需要再次反映页面类.因为控件存储在非公共实例字段中,所以这在部分信任中也不起作用.

无论您的应用程序无法以部分信任方式运行都是一个问题取决于您,但由于.NET 4的安全模型已经大大简化,因此可以非常轻松地运行部分信任的Web应用程序,这是我的事情.努力做到.

TLDR ; 总而言之,有可能这样做(例如参见本例),但由于ASP.NET Web Forms框架的局限性,您需要完全信任才能使其工作.

更新 Microsoft已从.NET 4.0开始废弃对ASP.NET的部分信任(在此处阅读).因此,从这个角度来看,远离完全信任可能不是那么有用(无论如何你都需要它).