网络表单和依赖注入

本文关键字:注入 依赖 表单 网络 | 更新日期: 2023-09-27 18:21:00

我正在将依赖注入框架引入到现有的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>();

显然,我不喜欢将所有这些对容器的引用分散在我的应用程序中,或者让我的页面/控件依赖项是非显式的,但我无法找到更好的方法。

对于将 DI 与 Web 窗体一起使用,是否有更优雅的解决方案?

网络表单和依赖注入

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

而是在 Global 类上创建一个静态Resolve<T>方法。这完全隐藏了容器,并允许您交换实现,而无需更改网页中的任何内容。执行此操作时,按照@Wiktor的建议使用公共服务定位器没有任何优势。公共服务定位器只是不必抽象的东西的另一个抽象(因为你已经使用Global.Resolve<T>抽象了容器(。

不幸的是,对于 Web 表单,实际上没有任何好方法可以做到这一点。对于简单注入器,我为 Web 窗体编写了一个集成指南,该指南基本上描述了 Global.Resolve<T> 方法的使用,但也展示了一种测试是否可以创建 Page 类的方法。该指南也可用于其他 DI 容器。

顺便说一句,请记住,对于温莎城堡,您请求的所有内容都必须显式发布(注册解析发布模式(。这有点讨厌 (IMO(,与其他容器的工作方式不同,当您不正确执行此操作时,可能会成为内存泄漏的来源。

最后一点。可以使用 Web 窗体进行构造函数注入。井。。。有点,因为这将使用默认构造函数创建Form后使用反射调用重载的构造函数,因此这会导致时间耦合。

对于将 DI 与 Web 窗体一起使用,是否有更优雅的解决方案?

是的,MVP 模式允许您在 WebForms 应用程序中完全分离关注点。一旦您实现了关注点分离和弱耦合,DI 就很容易了。

在 ASP.NET 内置的MVC中。

知道这已经很老了,但是现在,从.NET 4.7.2开始的WebForms中有DI。关于本文:ASP.NET 博客:在WebForms应用程序中使用依赖注入

只需安装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>();
}

希望对您有所帮助。

ASP.NET MVC 具有 IDependencyResolver 和一个静态管理器类,可让您获取和设置解析程序。我不喜欢在Web表单项目中引用System.Web.Mvc的想法,所以我选择了IServiceLocator,它做了同样的事情:

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();
    }
}

然后在您的页面类中...

IDriverService service = ServiceLocator.Current.GetInstance<IDriverService>();

或者通过构造函数注入连接 DI。我还没有走上网络表单的道路,所以其他人需要为我填写:)(我已经在MVC土地上生活了大约一年(。

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

正如

@DarinDimitrov所说,MVP模式是将DI/IOC与Webforms一起使用的方法。

您可以推出自己的实现或使用现有框架。我听说过WebForms MVP,但我实际上还没有使用过它。

根据文档,它通过Castle Windsor,Autofac和Unity内置了对DI的支持。它还为演示者提供基于约定的自动发现。

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

http://commonservicelocator.codeplex.com/