检索 Autofac 容器以解析服务

Retrieving Autofac container to resolve services

在 C# WindowForms 应用程序中,我启动了一个 OWIN WebApp,它创建了我的另一个 class Erp:

的单例实例
public partial class Engine : Form
{
    const string url = "http://*:8080"; //49396
    private IDisposable webApp;

    public Engine()
    {
        InitializeComponent();
        StartServer();
    }

    private void StartServer()
    {
        webApp = WebApp.Start<Startup>(url);
        Debug.WriteLine("Server started at " + url);
    }

    private void btnDoSomething(object sender, System.EventArgs e)
    {
       // needs to call a method in erp
    }
}

class Startup
{
    public void Configuration(IAppBuilder app)
    {
        Trace.Listeners.Remove("HostingTraceListener");
        app.UseCors(CorsOptions.AllowAll);

        var builder = new ContainerBuilder();
        var config = new HubConfiguration();
        builder.RegisterHubs(Assembly.GetExecutingAssembly()).PropertiesAutowired();
        var erp = new Erp();
        builder.RegisterInstance<Erp>(erp).SingleInstance();
        var container = builder.Build();
        config.Resolver = new AutofacDependencyResolver(container);
        app.UseAutofacMiddleware(container);
        app.MapSignalR(config);
    }
}

创建 WebApp 后,我想在代码的其他部分(即上面按钮的事件处理程序中)检索创建的单例 erp 实例。

据我所知,我需要使用 resolve 函数:

var erp = container.Resolve<Erp>();

但我不清楚如何在配置函数之外检索 container

我不会想太多。在某处设置一个静态变量并坚持下去。

public static class ContainerProvider
{
  public static IContainer Container { get; set; }
}

并在启动块中:

var container = builder.Build();
ContainerProvider.Container = container;
config.Resolver = new AutofacDependencyResolver(container);

现在您可以在任何需要的地方获得容器。

编辑:我刚刚意识到接受的答案是由 Autofac 项目的共同所有者提供的,这让我感到困惑,因为它似乎与文档中的内容相悖。我暂时留下答案,希望得到澄清。

只是想提供我自己的答案是因为虽然接受的答案有效;这通常被认为是不好的做法。

来自 Autofac 文档的 Best Practices and Recommendations 部分:

Use Relationship Types, Not Service Locators

Giving components access to the container, storing it in a public static property, or making functions like Resolve() available on a global “IoC” class defeats the purpose of using dependency injection. Such designs have more in common with the Service Locator pattern.

If components have a dependency on the container (or on a lifetime scope), look at how they’re using the container to retrieve services, and add those services to the component’s (dependency injected) constructor arguments instead.

Use relationship types for components that need to instantiate other components or interact with the container in more advanced ways.

你没有给出你想在代码中如何使用它的具体场景,所以我无法为你提供确切的解决方案,但是你有什么理由需要自己解决实例吗?你能不能只通过依赖注入来交付 Erp 实例?

如果答案是肯定的,我从 Autofac 文档中的 Windows Forms Integration Guide 页面改编的以下代码演示了如何完成此操作:

public partial class Form1 : Form {
    
    private readonly Erp _erp;

    public Form1(Erp erp) {
        this._erp = erp;

        InitializeComponent();
    }

    private void button1_Click(object sender, EventArgs e) {
        //do stuff with erp here
    }
}

然后 Autofac,假设注册设置正确,应该将实例注入 class。

希望对您有所帮助!