Asp.Net Core:注册实现多个接口和生活方式Singleton

时间:2017-01-23 16:25:15

标签: c# dependency-injection asp.net-core inversion-of-control

考虑以下接口和类定义:

public interface IInterface1 { }
public interface IInterface2 { }
public class MyClass : IInterface1, IInterface2 { }

有没有办法用这样的多个接口注册MyClass的一个实例:

...
services.AddSingleton<IInterface1, IInterface2, MyClass>();
...

并使用不同的接口解析此MyClass的单个实例:

IInterface1 interface1 = app.ApplicationServices.GetService<IInterface1>();
IInterface2 interface2 = app.ApplicationServices.GetService<IInterface2>();

4 个答案:

答案 0 :(得分:37)

根据定义,服务集合是ServiceDescriptor的集合,它们是服务类型和实现类型的对。

然而,您可以通过创建自己的提供程序函数来解决这个问题,比如这样(感谢user7224827):

services.AddSingleton<IInterface1>();
services.AddSingleton<IInterface2>(x => x.GetService<IInterface1>());

以下更多选项:

private static MyClass ClassInstance;

public void ConfigureServices(IServiceCollection services)
{
    ClassInstance = new MyClass();
    services.AddSingleton<IInterface1>(provider => ClassInstance);
    services.AddSingleton<IInterface2>(provider => ClassInstance);
}

另一种方式是:

public void ConfigureServices(IServiceCollection services)
{
    ClassInstance = new MyClass();
    services.AddSingleton<IInterface1>(ClassInstance);
    services.AddSingleton<IInterface2>(ClassInstance);
}

我们只提供相同的实例。

答案 1 :(得分:4)

保持DI机制的另一种方法是执行以下操作:

-- nbr of staff associated with each dept. 
SELECT count(departmentId) as freq
FROM staff
GROUP BY departmentId

-- nbr of students associated with each dept. 
SELECT count(departmentId) as freq
FROM StudentAssignment
GROUP BY departmentId

答案 2 :(得分:2)

上面的答案很酷,以此为灵感,我对其进行了更改,以利用框架附带的类型约束,从而避免在使用不兼容的类和接口时需要进行强制转换以及最有帮助的编译器错误.在运行时,编译器错误比“这他妈的为什么是 null”更容易解决;.)

[TestClass()]
public class ServiceCollectionExtensionTests
{
    interface MyInterface
    {
        Guid Id { get; }
    }
    class MyClas : MyInterface
    {
        Guid id = Guid.NewGuid();

        public Guid Id => id;

    }


    [TestMethod()]
    public void AddSingletonTest()
    {
        var service = new ServiceCollection()
                            .AddSingleton<MyClas>()
                            .ReUseSingleton<MyClas,MyInterface>()
                            .BuildServiceProvider();

        var foo1 = service.GetService<MyClas>();
        var foo2 = service.GetService<MyInterface>();
        Assert.AreEqual(foo1.Id, foo2.Id);
        Assert.AreSame(foo1, foo2);
    }
}

“ReUseXYZ”的代码在这里:

namespace Microsoft.Extensions.DependencyInjection
{
    /// <summary>
    /// Class ServiceCollectionExtension allowing to registered 
    /// derived implementations of a already registered service 
    /// to re-use the same service without having to register 
    /// the same class 2x ending up with 2 instances of the 
    /// same type in the same scope.
    /// </summary>
    public static class ServiceCollectionExtension
    {

        /// <summary>
        /// Adds a singleton service of the type specified in TBase with a factory based on the registered type T that has been specified in implementation factory to the specified <see cref="Microsoft.Extensions.DependencyInjection.IServiceCollection"/>.
        /// </summary>
        /// <typeparam name="T">The registered type</typeparam>
        /// <typeparam name="TBase">The type that T is derived from, can be the base class or base interface.</typeparam>
        /// <param name="services">The services.</param>
        /// <returns>the IServiceCollection used to register the interface with.</returns>
        public static IServiceCollection ReUseSingleton<T, TBase>(this IServiceCollection services)
            where T : TBase
            where TBase : class
        {
            services.AddSingleton<TBase>(a => a.GetRequiredService<T>());
            return services;
        }

        /// <summary>
        /// Adds a transient service of the type specified in TBase with a factory based on the registered type T that has been specified in implementation factory to the specified <see cref="Microsoft.Extensions.DependencyInjection.IServiceCollection"/>.
        /// </summary>
        /// <typeparam name="T">The registered type</typeparam>
        /// <typeparam name="TBase">The type that T is derived from, can be the base class or base interface.</typeparam>
        /// <typeparam name="TS">The IServiceCollection instance to extend.</typeparam>
        /// <param name="services">The services.</param>
        /// <returns>the IServiceCollection used to register the interface with.</returns>
        public static IServiceCollection ReUseTransient<T, TBase>(this IServiceCollection services)
            where T : TBase
            where TBase : class

        {
            services.AddTransient<TBase>(a => a.GetRequiredService<T>());
            return services;
        }

        /// <summary>
        /// Adds a scoped service of the type specified in TBase with a factory based on the registered type T that has been specified in implementation factory to the specified <see cref="Microsoft.Extensions.DependencyInjection.IServiceCollection"/>.
        /// </summary>
        /// <typeparam name="T">The registered type</typeparam>
        /// <typeparam name="TBase">The type that T is derived from, can be the base class or base interface.</typeparam>
        /// <typeparam name="TS">The IServiceCollection instance to extend.</typeparam>
        /// <param name="services">The services.</param>
        /// <returns>the IServiceCollection used to register the interface with.</returns>
        public static IServiceCollection ReUseScoped<T, TBase>(this IServiceCollection services)
            where T : TBase
            where TBase : class
        {
            services.AddScoped<TBase>(a => a.GetRequiredService<T>());
            return services;
        }
    }
}

答案 3 :(得分:0)

您可以包装user7224827的答案以创建一个与原始所需API匹配的不错的扩展方法:

Receipt()