除了将 DI 容器引用存储在 Application 变量中之外,还有其他选择吗?

Is there any alternative to storing the DI container reference in Application variable?

我有一个 C# MVC 应用程序。我正在使用 Unity Container 来解决我的依赖关系。为了在 MVC 控制器中注入依赖项,我使用了构造函数注入。为了实现这一点,我在 Application_Start 事件即

上用我的 Controller Builder 工厂替换了 MVC Controller Builder 工厂
protected void Application_Start() 
{    
 IUnityContainer container = new UnityContainer();

 //All container registrations ....

ControllerBuilder.Current.SetControllerFactory(new 
UnityControllerFactory(container)); 

//Store reference of container in application object
HttpContext.Current.Application["Injector"] = container;   
}

但是我需要容器实例来解决某些无法进行构造函数注入的地方的依赖关系,例如Application_AuthenticateRequest 事件。因此,作为后备,我在 Application 对象中存储了对容器的引用。我用这个实例来解析引用。

protected void Application_AuthenticateRequest(object sender, EventArgs e)
{
 var container = HttpContext.Current.Application["Injector"] as 
 IUnityContainer;
 var service = container.Resolve<IService>();
}

是否可以将容器引用存储在应用程序变量中,或者是否有任何其他建议的做法? 我也知道有属性注入。我可以在这种情况下使用它吗?

我们有一个 custom UnityResolver,在 Application_Start() 中,我们配置(通过 GlobalConfiguration.Configure([...]),但我猜你可以这样做)解析器是这样的:

public static void Register(HttpConfiguration config)
{   
    UnityContainer container = new UnityContainer();

    // This contains our actual container registrations.    
    UnityRegistrer.Register(container); 

    // IoC for WebAPI
    config.DependencyResolver = new UnityResolver(container);

    // IoC for WebForms
    HttpContext.Current.Application.SetContainer(container);

    // IoC for MVC5
    DependencyResolver.SetResolver(new UnityDependencyResolver(container));

    // Configure other stuff like routes, tracing, error handling, authorization, etc.
}

我不是 Web 开发方面的专家,所以也许您想调整一些东西,但这对我们来说效果很好。

您应该努力防止从应用程序代码中访问容器。然而,在 Composition Root 中,直接访问容器通常是可以的,而且通常无法阻止这种情况。您的 Application_AuthenticateRequest 可以被视为您的 Composition Root 的一部分,因此可以访问容器(而且确实没有办法绕过它)。

但是您可以将代码简化为以下内容:

private static IUnityContainer container;

protected void Application_Start() 
{    
    container = new UnityContainer();

    ...
}

protected void Application_AuthenticateRequest(object sender, EventArgs e)
{
    var service = container.Resolve<IService>();
}