IServiceProvider不返回Singleton实例

时间:2016-12-13 10:35:35

标签: c# .net dependency-injection .net-core

我遇到了.Net Core,我正面临着它的DI引擎。

我的项目是一个类库,因此,asp的绑定在这里无关紧要。

我按照this article的提示进行DI工作。

现在,到了多汁的部分:

我已经建立了一个如下所示的服务提供商:

public static class ServiceProvider
    {
        public static IServiceProvider GetServiceProvider()
        {
            var services = new ServiceCollection();

            //Singletons
            services.AddSingleton<IInstance, Instance>();

            //Transients
            services.AddTransient<IDate, Date>();
            services.AddTransient<IMath, Math>();
            services.AddTransient<INumber, Number>();
            return services.BuildServiceProvider();
        }
    }

然后我尝试在一个看起来像这样的静态类中执行它:

public static class MySingleton
    {
        public static IInstance Instance
            => ServiceProvider.GetServiceProvider().GetService<IInstance>();
    }

并且为了测试单例行为,我测试了它:

[Test]
        public void Instance_HundredTimes_ReturnsSameInstance()
        {
            //Arrange
            const int callCount = 100;
            var results = new IInstance[callCount];

            //Act
            for (var i = 0; i < callCount; i++)
            {
                results[i] = MySingleton.Instance;
            }

            //Assert
            Assert.That(results.Distinct().Count(), Is.EqualTo(1));
        }

测试结果显示为负数,而不是在distinct之后有一个引用(因为它是一个单例),我仍然留下了一百个实例。

我做错了吗?

我在配置中遗漏了什么吗?

2 个答案:

答案 0 :(得分:2)

您的问题出在此代码块中:

public static class MySingleton
{
    public static IInstance Instance
        => ServiceProvider.GetServiceProvider().GetService<IInstance>();
}

您在这里所做的是每次访问该物业时都致电ServiceProvider.GetServiceProvider().GetService<IInstance>() 。这意味着实际上没有单身人士。你想要做的是设置一次单例实例:

public static class MySingleton
{
    public static IInstance Instance
    {
        get;
    } = ServiceProvider.GetServiceProvider().GetService<IInstance>();
}

此外,您在创建服务时遇到类似问题。每次致电ServiceCollection时,您都会创建一个新的GetServiceProvider()。你可能不想要那个。你可能想要这样的东西:

public static class ServiceProvider
{
    private static IServiceProvider serviceProvider = null;

    public static IServiceProvider GetServiceProvider()
    {
        if (serviceProvider == null) 
        {
            var services = new ServiceCollection();

            //Singletons
            services.AddSingleton<IInstance, Instance>();

            //Transients
            services.AddTransient<IDate, Date>();
            services.AddTransient<IMath, Math>();
            services.AddTransient<INumber, Number>();

            serviceProvider = services.BuildServiceProvider();
        }
        return serviceProvider;
    }
}

答案 1 :(得分:0)

问题:

我的问题在于不将我的IserviceProvider实例保留在MySingleton

解决方案:

<强> TL; DR

有一个IserviceProvider

的静态实例

代码重构

重构ServiceProvider看起来如下:

公共类LodashServiceProvider     {         private static readonly Lazy LazyServiceProvider;

    static LodashServiceProvider()
    {
        LazyServiceProvider = new Lazy<IServiceProvider>(InitializeServiceProvider);
    }

    public static IServiceProvider GetServiceProvider() => LazyServiceProvider.Value;

    private static IServiceProvider InitializeServiceProvider()
    {
        var services = new ServiceCollection();

        //Singletons
        services.AddSingleton<ILodashInstance, LodashInstance>();

        //Transients
        services.AddTransient<ILodashDate, LodashDate>();
        services.AddTransient<ILodashMath, LodashMath>();
        services.AddTransient<ILodashNumber, LodashNumber>();
        return services.BuildServiceProvider();
    }
}

我要感谢Kiziu&amp; Sefe解决问题的方法。