访问或获取静态类中的Autofac容器

本文关键字:Autofac 容器 静态类 获取 访问 | 更新日期: 2023-09-27 18:24:39

我需要在一个静态类中获取或访问我的IoC容器。这是我的(简化的)场景:

我在Startup类中注册ASP.net Web Api的依赖项(但我也为MVC或WCF注册依赖项。我有一个DependencyResolver项目,但为了简单起见,请考虑以下代码)

// Web Api project - Startup.cs
public void Configuration(IAppBuilder app)
{
    HttpConfiguration config = new HttpConfiguration();
    var builder = new ContainerBuilder();
    // ... Omited for clarity
    builder.RegisterAssemblyTypes(AppDomain.CurrentDomain.GetAssemblies())
        .AsClosedTypesOf(typeof(IHandle<>))
        .AsImplementedInterfaces();
    // ...
    IContainer container = builder.Build();
    config.DependencyResolver = new AutofacWebApiDependencyResolver(container);
    // ...
}

然后,在一个单独的类库中,我有一个静态类(为了清晰起见,再次简化):

public static class DomainEvents
{
    private static IContainer Container { get; set; }
    static DomainEvents()
    {
        //Container = I need get my Autofac container here
    }
    public static void Register<T>(Action<T> callback) where T : IDomainEvent { /* ... */ }
    public static void ClearCallbacks() { /* ... */  }
    public static void Raise<T>(T args) where T : IDomainEvent
    {
        foreach (var handler in Container.Resolve<IEnumerable<IHandle<T>>>())
        {
            handler.Handle(args);
        }
        // ...
    }
}

知道我怎么才能拿到这个吗?

访问或获取静态类中的Autofac容器

我需要在一个静态类中获取或访问我的IoC容器。知道我怎么才能拿到这个吗?

是的,你没有!认真地带有静态DomainEvents类的模式源自Udi Dahan,但即使是Udi也承认这是一个糟糕的设计。需要依赖关系的静态类使用起来非常痛苦。它们使系统难以测试和维护。

相反,创建一个IDomainEvents抽象,并将该抽象的实现注入到需要发布事件的类中。这完全解决了你的问题。

您可以如下定义DomainEvents类:

public interface IDomainEvents
{
    void Raise<T>(T args) where T : IDomainEvent;
}
// NOTE: DomainEvents depends on Autofac and should therefore be placed INSIDE
// your Composition Root.
private class AutofacDomainEvents : IDomainEvents
{
    private readonly IComponentContext context;
    public AutofacDomainEvents(IComponentContext context) {
        if (context == null) throw new ArgumentNullException("context");
        this.context = context;
    }
    public void Raise<T>(T args) where T : IDomainEvent {
        var handlers = this.context.Resolve<IEnumerable<IHandle<T>>>();
        foreach (var handler in handlers) {
            handler.Handle(args);
        }
    }
}

您可以按如下方式注册此类:

IContainer container = null;
var builder = new ContainerBuilder();
builder.RegisterType<AutofacDomainEvents>().As<IDomainEvent>()
    .InstancePerLifetimeScope();
// Other registrations here
container = builder.Build();

您可以在DomainEvents类中创建一个静态方法来注入容器,如下所示:

public static class DomainEvents
{
    public static void SetContainer(IContainer container)
    {
        Container = container;
    }
    ....
}

然后从您的ASP.NET应用程序中,调用此方法来注入容器:

DomainEvents.SetContainer(container);

请注意,我直接回答你的问题。然而,我看到了一些问题:

  • 当类需要依赖关系时,不应使用静态类。在这种情况下,重构以使用非静态类,并使用构造函数注入在类中注入所需的依赖项
  • 在CompositionRoot之外使用容器被称为ServiceLocation,并且被认为是一种反模式
  • 类库不应该使用容器,甚至不应该具有Composition根。引用我引用的Composition Root文章:

只有应用程序应该具有Composition Roots。库和框架不应该。