首页 > 解决方案 > 向 ASP.NET Core 注册现有的 Autofac 容器

问题描述

我目前正在构建一个通过 TCP 使用自定义协议的服务器应用程序。此服务器应用程序当前使用 Autofac 进行依赖注入。

不过最近,我在解决方案中添加了一个 ASP.NET Core 项目,以提供一个 HTTP API 来操作服务器应用程序,主要是提供一个管理 Web 应用程序。

Autofac 为 ASP.NET Core 项目提供集成,但我很难弄清楚如何告诉 ASP.NET Core 服务配置使用我已经构建的 Autofac 服务容器,以便我的 TCP 服务和 HTTP API可以从同一个容器中解析服务。

Autofac为此提供了文档:

public IServiceProvider ConfigureServices(IServiceCollection services)
{
    // Add services to the collection.
    services.AddMvc();

    // Create the container builder.
    var builder = new ContainerBuilder();

    builder.Populate(services);
    builder.RegisterType<MyType>().As<IMyType>();
    this.ApplicationContainer = builder.Build();

    // Create the IServiceProvider based on the container.
    return new AutofacServiceProvider(this.ApplicationContainer);
    //                                                   ^
    // This is where I'd like to insert my container ━━━━┛
}

该示例仅展示了如何从头开始为 ASP.NET Core 应用程序构建一个完整的容器,但现在展示了如何重用现有容器。

在 an 上使用该ConfigureServices方法在IWebHostBuilder这里不起作用,因为它的返回类型为void,所以我不能在AutofacServiceProvider那里返回 an 。

这是我启动应用程序的方式:

var containerBuilder = new ContainerBuilder();

// Here's where I register all my services
containerBuilder.RegisterModule(new ApplicationModule());
var container = containerBuilder.Build();

using (var scope = container.BeginLifetimeScope())
{

    var server = scope.Resolve<TcpServer>();

    var isService = args.Contains("--winservice");

    // Construct the HTTP API
    var builder = WebHost
        .CreateDefaultBuilder(args.Where(arg => arg != "--winservice").ToArray())
        .ConfigureServices(collection =>
        {
            // Not sure what to do here?
            // I can call `collection.AddAutofac` here, not sure what that does
        })
        .UseStartup<ApplicationAPI>();

    // Start the HTTP API
    if (isService)
    {
        // Run as a Win Service
        builder.Build().RunAsCustomService(server);
    }
    else
    {
        await server.Start();

        // Do not run as a Win Service
        builder.Build().Run();
    }
}

那么如何使用同一个容器来解决我的 TCP 服务器和 HTTP API 中的依赖关系呢?

谢谢!

标签: c#asp.net-coreautofac

解决方案


您还可以尝试提供聚合服务提供程序,类似于此处提供的服务提供程序(https://github.com/kephas-software/kephas/blob/master/src/Kephas.Composition.DependencyInjection/Composition/DependencyInjection/AggregatedServiceProvider。 )

/// <summary>
/// An aggregated service provider.
/// </summary>
public class AggregatedServiceProvider : IServiceProvider, IDisposable
{
    private readonly IList<IServiceProvider> innerServiceProviders;

    /// <summary>
    /// Initializes a new instance of the <see cref="AggregatedServiceProvider"/> class.
    /// </summary>
    /// <param name="innerServiceProviders">A variable-length parameters list containing inner
    ///                                     service providers.</param>
    public AggregatedServiceProvider(params IServiceProvider[] innerServiceProviders)
    {
        this.innerServiceProviders = innerServiceProviders.ToList();
    }

    /// <summary>
    /// Gets the service object of the specified type.
    /// </summary>
    /// <param name="serviceType">An object that specifies the type of service object to get.</param>
    /// <returns>
    /// A service object of type <paramref name="serviceType">serviceType</paramref>.   -or-  null if
    /// there is no service object of type <paramref name="serviceType">serviceType</paramref>.
    /// </returns>
    public object GetService(Type serviceType)
    {
        foreach (var serviceProvider in this.innerServiceProviders)
        {
            var service = serviceProvider.GetService(serviceType);
            if (service != null)
            {
                return service;
            }
        }

        return null;
    }

    /// <summary>
    /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged
    /// resources.
    /// </summary>
    public void Dispose()
    {
        foreach (var serviceProvider in this.innerServiceProviders)
        {
            (serviceProvider as IDisposable)?.Dispose();
        }

        this.innerServiceProviders.Clear();
    }
}

然后,将您在配置服务中的代码更改为:

return new AgregegatedServiceProvider(new ServiceProvider(services), myAutofacContainer);

缺点是来自 ASP.NET Core 的服务对您的 Autofac 容器不可用,但是,正如我所见,这对您来说应该不是问题。


推荐阅读