创建 ServiceProvider 后是否可以执行代码?

Is it possible to execute code after the ServiceProvider is created?

我有一个 ASP.NET 基于 Core 3.1 WebApi 的项目,它是用 C# 编写的。我想在应用程序完成引导时执行一次代码。

例如,我想在创建 IServiceProvider 后执行以下代码,以避免必须创建 IServiceProvider.

的第二个实例

我认为在 IServiceCollection 扩展上使用 .AddOptions() 将允许我定义一个函数,稍后将在创建 IServiceProvider 后调用该函数。但好像不是这样。

这是我所做的。在 ConfigureServices(IServiceCollection services) 方法中我添加了以下代码

services.AddOptions()
        .Configure<IServiceProvider>((serviceProvider) =>
        {
            var items = serviceProvider.GetServices<ICustomInterface>();

            foreach (ICustomInterface item in items)
            {
                item.DoSome();
            }
        });

但是 Configure<IServiceProvider>() 中的代码永远不会被调用。

构建IServiceProvider后如何调用我的自定义代码?

考虑您的 program.cs 文件。通常,您会在此处看到 .....Build().Run() 代码以启动您的 Web 服务。

如果您拆分构建和 运行 阶段,您可以在服务开始为请求提供服务之前评估服务提供商。

            var host = Host.CreateDefaultBuilder(args)
                .ConfigureWebHostDefaults(webBuilder =>
                {
                    webBuilder.UseStartup<Startup>();
                }).Build();

            // Do your initialization here
            var serviceProvider = host.Services;

            var items = serviceProvider.GetServices<ICustomInterface>();

            foreach (ICustomInterface item in items)
            {
                item.DoSome();
            }

            // Start your service
            host.Run();

如果您已经看过 DefaultServiceProviderFactory 的源代码,那么是的,您可以拥有自己的 ServiceProviderFactory 作为默认值并获得好处 to execute code after the ServiceProvider is created .

ExampleServiceProviderFactory.cs

public class ExampleServiceProviderFactory : IServiceProviderFactory<IServiceCollection>
{
    private readonly ServiceProviderOptions _options;

    public ExampleServiceProviderFactory(ServiceProviderOptions options)
    {
        if (options == null)
            throw new ArgumentNullException(nameof(options));

        _options = options;
    }

    public IServiceProvider CreateServiceProvider(IServiceCollection containerBuilder)
    {
        var serviceProvider =  containerBuilder.BuildServiceProvider(_options);

        // TODO: here you go
        var items = serviceProvider.GetServices<ICustomInterface>();

        foreach (ICustomInterface item in items)
        {
            item.DoSome();
        }

        return serviceProvider;
    }
}

在 statrup 上使用此 ServiceProviderFactory 而不是 DefaultServiceProviderFactory 的更简单快捷的方法是这样的,

Program.cs

Host.CreateDefaultBuilder(args)
    .UseServiceProviderFactory((context) =>
    {
        var options = new ServiceProviderOptions()
        {
            ValidateOnBuild = false, // default,
            ValidateScopes = context.HostingEnvironment.IsDevelopment(),
        };
        return new CustomServiceProviderFactory(options);
    })