簡體   English   中英

在靜態類中訪問或獲取Autofac Container

[英]Access or get Autofac Container inside a static class

我需要在靜態類中獲取或訪問我的IoC容器。 這是我的(簡化)場景:

我在一個Startup類中注冊ASP .net Web Api的依賴項(但我也是為MVC或WCF注冊的。我有一個DependecyResolver項目,但為了簡單起見,請考慮以下代碼)

// 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);
        }
        // ...
    }
}

知道我怎么能得到這個?

我需要在靜態類中獲取或訪問我的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);

請注意,我將直接回答您的問題。 但是,我在這里看到了一些問題:

  • 當類需要依賴項時,不應使用靜態類。 在這種情況下,重構使用非靜態類並使用構造函數注入來注入類中所需的依賴項。
  • 使用Composition Root外部的容器稱為服務位置, 並被視為反模式
  • 類庫不應該使用容器,甚至不能使用Composition Root。 引用我引用的Composition Root文章:

只有應用程序應具有組合根。 圖書館和框架不應該。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM