繁体   English   中英

.NET Core DI,为包注册默认实现

[英].NET Core DI, register a default implementation for a package

如何使用 .NET Core 的 IoC 容器注册默认实现并提供覆盖现有实现的方法?

例如,我可能想创建一个包,为某些服务提供默认实现。

namesapce Package 
{
    public interface ISomeService { }

    public class Default : ISomeService { }
}

然后在同一个包中使用此服务。

namesapce Package 
{
    public class Service 
    {
        Service(ISomeService service) { }
    }
}

如何注册ISomeService默认实现?

稍后在某些项目中使用此包并希望用另一个覆盖现有实现时,应将默认值替换为 Override。

namespace Project 
{
    public class Override : ISomeService { }
}

如果您的包包含配置IServiceCollection的类,例如:

public class MyPackageInstaller
{
    public void Install(IServiceCollection services)
    {
        // Your package registers its services
    }
}

那么这也可以是您允许消费者进行可选更改的地方。 例如,您可以定义一个这样的类,它允许消费者为某些服务指定实现:

public class MyPackageRegistrationOptions
{
    public ServiceDescriptor FooServiceDescriptor { get; private set; }

    public void AddFooService(ServiceDescriptor fooDescriptor)
    {
        if (fooDescriptor.ServiceType != typeof(IFooService))
        {
            throw new ArgumentException("fooDescriptor must register type IFooService.");
        }
        FooServiceDescriptor = fooDescriptor;
    }
}

现在,您的安装程序可以采用这些选项,并注册使用者指定的实现或它自己的默认实现。

public class MyPackageInstaller
{
    private readonly MyPackageRegistrationOptions _options;

    public MyPackageInstaller(MyPackageRegistrationOptions options = null)
    {
        _options = options;
    }
    public void Install(IServiceCollection services)
    {
        if (_options?.FooServiceDescriptor != null)
            services.Add(_options.FooServiceDescriptor);
        else 
             // here's your default implementation
            services.AddSingleton<FooService>();
    }
}

用法:

var services = new ServiceCollection();
var options = new MyPackageRegistrationOptions();
options.AddFooService(ServiceDescriptor.Singleton<IFooService, AlternateFooService>());
var installer = new MyPackageInstaller(options);
installer.Install(services);

乍一看,获得相同结果的方法似乎更长。 好处是它允许您更清楚哪些服务应该或不应该被覆盖。 这样,感觉更像是您在使用故意公开的配置选项,而不是在包的内部进行检查。

您可以允许消费者仅指定服务类型,而不是允许消费者添加ServiceDescriptor ,而您的配置决定了它如何注册(单例、瞬态等)

当库依赖于必须由使用者提供的连接字符串等配置值时,这也是一种有用的模式。 您可以使它们成为构造选项的必需参数,然后需要这些选项来构造安装程序,或者仅将它们设置为安装程序中的必需参数。 现在不可能在没有所需配置值的情况下安装包。

内置的 .NET Core DI 容器允许应用程序开发人员通过简单地将相同的服务附加到ServiceCollection来覆盖您的包注册到ServiceCollection 如果对单一服务类型进行了多次注册,则将使用最后一次注册。 例如:

// Package registrations (part of your Package)
services.AddTransient<ISomeService, Default>();

// Override by application developer (part of his Startup.cs)
services.AddTransient<ISomeService, Override>();

务必考虑以不需要使用 DI 容器的方式构建您的包,如 Mark Seemann 在他的DI-Friendly Library文章中所述。

你可以在你的包中注册任何你想要的服务并通过接口公开它们。 然后,当您将它用于某个项目时,覆盖默认包实现所需要做的就是覆盖公开的接口之一,即 .

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM