C# Webforms和依赖注入

C# Webforms和依赖注入,c#,asp.net,dependency-injection,webforms,castle-windsor,C#,Asp.net,Dependency Injection,Webforms,Castle Windsor,我正在将依赖注入框架引入现有的WebForms应用程序(使用Castle Windsor) 我对DI有很深的经验,并且倾向于非常强烈地支持构造函数注入而不是setter注入。如果您熟悉Webforms,您就会知道ASP.Net框架处理页面和控件对象的构造,这使得真正的构造函数注入变得不可能 我当前的解决方案是在Global.asax的Application_Start事件中注册容器,并将容器作为公共静态变量保存在Global中。然后,我只需在需要时直接在页面或控件中解析所需的每个服务。因此,在每

我正在将依赖注入框架引入现有的WebForms应用程序(使用Castle Windsor)

我对DI有很深的经验,并且倾向于非常强烈地支持构造函数注入而不是setter注入。如果您熟悉Webforms,您就会知道ASP.Net框架处理页面和控件对象的构造,这使得真正的构造函数注入变得不可能

我当前的解决方案是在Global.asax的Application_Start事件中注册容器,并将容器作为公共静态变量保存在Global中。然后,我只需在需要时直接在页面或控件中解析所需的每个服务。因此,在每一页的顶部,我都会编写如下代码:

private readonly IMyService _exposureManager = Global.IoC.Resolve<IMyService>();
private readonly IMyOtherService _tenCustomersExposureManager = Global.IoC.Resolve<IMyOtherService>();
private readonly IMyService\u exposureManager=Global.IoC.Resolve();
private readonly IMyOtherService_tenCustomersExposureManager=Global.IoC.Resolve();
显然,我不喜欢将所有这些对容器的引用分散在我的应用程序中,或者让我的页面/控件依赖项不显式,但我一直没有找到更好的方法

对于将DI与Webforms一起使用,有没有更优雅的解决方案

对于将DI与Webforms一起使用,有没有更优雅的解决方案

是的,允许您在WebForms应用程序中清晰地分离关注点。一旦分离了关注点和弱耦合,DI就很容易了


在ASP.NET MVC中,它是内置的。

实际上,您刚刚构建的是您自己的服务定位器实现。但是,几乎可以肯定的是,您选择的IoC框架已经有了一个实现

ASP.NET MVC具有和,可用于获取和设置冲突解决程序。我不喜欢在Web表单项目中引用System.Web.Mvc,所以我选择了,它做了同样的事情:

public static class Bootstrapper
{
    private static readonly IUnityContainer _container = new UnityContainer();

    public static void Initialize()
    {
        ServiceLocator.SetLocatorProvider(() => new UnityServiceLocator(_container));

        _container.RegisterType<IDriverService, DriverService>();
    }

    public static void TearDown()
    {
        _container.Dispose();
    }
}

public class Global : HttpApplication
{
    protected void Application_Start(object sender, EventArgs e)
    {
        Bootstrapper.Initialize();
    }

    protected void Application_End(object sender, EventArgs e)
    {
        Bootstrapper.TearDown();
    }
}
公共静态类引导程序
{
私有静态只读IUnityContainer_container=new UnityContainer();
公共静态void Initialize()
{
SetLocatorProvider(()=>新的UnityServiceLocator(_容器));
_container.RegisterType();
}
公共静态void拆卸()
{
_container.Dispose();
}
}
公共类全局:HttpApplication
{
受保护的无效应用程序\u启动(对象发送方,事件参数e)
{
Bootstrapper.Initialize();
}
受保护的无效应用程序\u结束(对象发送方,事件参数e)
{
Bootstrapper.TearDown();
}
}
然后在你的页面类

IDriverService service = ServiceLocator.Current.GetInstance<IDriverService>();
IDriverService service=ServiceLocator.Current.GetInstance();
或者通过构造函数注入连接DI。我还没有开始使用web表单,所以需要其他人来帮我填写:)(我已经在MVC领域生活了大约一年了)


我的示例使用Unity,但您应该能够相当容易地将其应用于任何其他DI实现。

正如@DarinDimitrov所说,MVP模式是将DI/IOC与Webforms结合使用的方法

您可以推出自己的实现,也可以使用现有的框架。我听说过很多,但我还没有真正使用过


据介绍,它已通过温莎城堡、Autofac和Unity为DI提供支持。它还为演示者提供了基于约定的自动发现功能

我同意@DarinDimitrov的观点,MVP是一个有趣的选择。然而,在使用遗留应用程序时,将现有页面重写为MVP模式是一项非常艰巨的工作。在这种情况下,最好从服务定位器模式(但仅在UI类中)开始,就像您已经在做的那样。然而,要改变一件事。不要向应用程序公开所选的DI容器,我希望您使用的是
Global.IoC
属性

相反,在
Global
类上创建一个静态
Resolve
方法。这将完全隐藏容器,并允许您交换实现,而无需更改网页中的任何内容。当您这样做时,使用@Wiktor建议的公共服务定位器没有任何好处。公共服务定位器只是对不必抽象的东西的另一种抽象(因为您已经使用
Global.Resolve
)抽象了容器)

不幸的是,对于Web表单,实际上没有任何好的方法可以做到这一点。例如,我写了一篇文章,基本上描述了
Global.Resolve
方法的使用,但也展示了一种测试是否可以创建页面类的方法。该指南也可用于其他DI容器

顺便说一句,请记住,对于Castle Windsor,您请求的所有内容都必须明确发布(the)。这有点令人讨厌(IMO),与其他容器的工作方式不同,如果操作不正确,可能会导致内存泄漏


最后一点。好。。。在某种程度上,因为这将在使用默认构造函数创建
表单之后使用反射调用重载构造函数,所以这会导致。

知道这很旧,但是现在,WebForms中有DI,从.NET 4.7.2开始。关于本条:

只需安装
Microsoft.AspNet.WebFormsDependencyInjection.Unity
包并在
Global.asax
中注册您的类:

protected void Application_Start(object sender, EventArgs e)
{
    var container = this.AddUnity();

    container.RegisterType<IPopularMovie, MovieManager>();
    container.RegisterType<IMovieRepository, XmlMovieRepository>();
}
受保护的无效应用程序\u启动(对象发送方,事件参数e)
{
var container=this.AddUnity();
container.RegisterType();
container.RegisterType();
}

希望能有所帮助。

在应用程序端执行
拆卸操作真的有用吗?应用程序域仍在卸载中。只有当您注册的单例服务在其
Dispose
方法中具有拆卸逻辑,但仍然很脆弱时,它才有用,因为无法保证所有这些
Dispose
方法在卸载AppDomain时实际运行。问得好。我只是试着跟着这条路走