.net core DI 中的多次注册可能产生的影响

Fot*_*kis 2 dependency-injection .net-core

.net core的DI中如果有多个服务注册会出现什么不好的情况吗?例如,假设我们有以下代码

public void ConfigureServices(IServiceCollection services)
{
    //....
    services.AddHealthChecks();
    //...
}
Run Code Online (Sandbox Code Playgroud)

在另一个(可能是扩展)类中我们services.AddHealthChecks()再次使用。这会不会弄乱 DI 的容器?

提前致谢

Moh*_*our 6

您可以多次注册服务而不会引发异常。问题是当您在不同的范围内多次注册服务时。考虑以下示例:

public interface IMyInterface
{
    void Print();
}

public class MyInterface : IMyInterface
{
    public void Print()
    {
    }
}
Run Code Online (Sandbox Code Playgroud)

让我们注册IMyInterface两个不同的范围:

internal class Program
{
    private static void Main(string[] args)
    {
        IServiceCollection services = new ServiceCollection();
        services.AddScoped<IMyInterface, MyInterface>();
        services.AddSingleton<IMyInterface, MyInterface>();

        var provider = services.BuildServiceProvider();

        for (var i = 0; i < 5; i++)
        {
            var scope = provider.CreateScope();
            using (scope)
            {
                var myInterface = scope.ServiceProvider.GetService<IMyInterface>();
                Console.WriteLine(myInterface.GetHashCode());
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

首先,IMyInterface按以下顺序注册:

services.AddScoped<IMyInterface, MyInterface>();
services.AddSingleton<IMyInterface, MyInterface>();
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述

正如你所看到的,我们得到了一个单例实例,MyInterface并且哈希码是相同的。

现在我们把它改成这样:

services.AddSingleton<IMyInterface, MyInterface>();
services.AddScoped<IMyInterface, MyInterface>();

Run Code Online (Sandbox Code Playgroud)

在此输入图像描述

现在我们得到了范围类型,MyInterface并且哈希码每次都不同。您始终可以获得您的类型的最后注册范围。

看一下AddHealthChecks代码:

services.AddScoped<IMyInterface, MyInterface>();
services.AddSingleton<IMyInterface, MyInterface>();
Run Code Online (Sandbox Code Playgroud)

通过添加services.AddHealthChecks();多次,您只需注册HealthCheckServiceIHostedService作为单例服务,我认为这不会影响健康检查功能。

通过以下扩展,您可以找到重复注册:

services.AddSingleton<IMyInterface, MyInterface>();
services.AddScoped<IMyInterface, MyInterface>();

Run Code Online (Sandbox Code Playgroud)

并以这种方式使用它:

public static IHealthChecksBuilder AddHealthChecks(this IServiceCollection services)
{
    services.TryAddSingleton<HealthCheckService, DefaultHealthCheckService>();
    services.TryAddEnumerable(ServiceDescriptor.Singleton<IHostedService, HealthCheckPublisherHostedService>());
    return new HealthChecksBuilder(services);
}
Run Code Online (Sandbox Code Playgroud)

阅读本文以获取更多详细信息。