0

我想在我现在正在做的项目中应用依赖注入并使用 Unity。在 Global.asax 文件的事件中注册类型Application_Start并将 Unity Conatiner 保留在 Application 对象全局变量中。但是,在解析演示者实例之前,我需要将当前 webform 的实例作为构造函数参数传递给演示者。我在页面的 OnInit 事件中执行此操作。

protected override void OnInit(EventArgs e)
{
    IUnityContainer container = (IUnityContainer)
        HttpContext.Current.Application["container"];

    container.RegisterInstance<IAddRoleView>(this, 
        new ExternallyControlledLifetimeManager());

    _presenter = container.Resolve<AddRolePresenter>();
    base.OnInit(e);
}

我的问题是:

  1. AddRoleView服务请求后,实例会发生什么?
  2. 它会被垃圾收集还是 Unity 容器在应用程序关闭之前始终保持引用,因为 Unity Conatiner 实例已保存在应用程序对象中?
4

1 回答 1

1

你正在做的事情是行不通的。您正在将页面实例注册为容器中的单例。这行不通。根据 Unity 的构建方式,它会在您第二次调用时抛出异常RegisterInstance<IAddRoleView>,永久缓存所有已注册的实例,或者替换之前的实现。但是,即使它替换了之前的注册,您的代码中也存在并发错误,因为可能会在AddRolePreventer针对此Page实例解决的问题中注入不同的页面。

我了解您要达到的目标。你想要解析AddRolePresenter,并且想要将页面注入到演示者的构造函数中。您通过它们的构造函数使两种类型相互依赖,这会导致循环依赖。您需要通过将页面注入到演示者的属性中来打破这种依赖循环。但是不要让 Unity 将页面注入到构造函数中;手动执行此操作:

_presenter = container.Resolve<AddRolePresenter>();
_presenter.View = this;

一些技巧:

  • 防止在初始化阶段后(运行Application_Start)进行任何注册。在初始化阶段之后添加注册通常被认为是不好的做法,因为它会使配置变得脆弱,并且难以维护。
  • 将此页面初始化在您解析演示者的位置移动到页面的构造函数。这使您可以更轻松地验证是否可以创建页面并在启动应用程序期间(甚至在单元测试中)执行此操作。看一下这里的例子,看看如何做到这一点的例子(它是另一个 DI 框架的文档,但它也适用于 Unity)。
  • 防止将容器存储在 HttpContext.Application 字典中。这使得在错误的地方使用容器变得很容易,并且将您的应用程序与 Unity 耦合太多。这可以防止您为另一个框架进行重构或更改 Unity(您将来肯定会这样做)。再看看这个例子。它还展示了将容器与 Web 表单集成的更好方法
于 2012-06-25T09:49:23.257 回答