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

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

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

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

namesapce Package 
{
    public interface ISomeService { }

    public class Default : ISomeService { }
}

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

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

如何注册ISomeService默认实现?

稍后,当在某些项目中使用此包并希望用另一个包覆盖现有实现时,应将 Default 替换为 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,并且您的配置决定它的注册方式(单例、 transient 等)

当库依赖于配置值(例如必须由使用者提供的连接字符串)时,这也是一种有用的模式。您可以将它们设置为构建选项的必需参数,然后将它们设置为构建安装程序所需的参数,或者仅将它们设置为安装程序中的必需参数。现在,如果没有所需的配置值,就无法安装该软件包。

关于c# - .NET Core DI,为包注册默认实现,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56255424/

相关文章:

c# - 请推荐内部共享源代码的解决方案

c# - AspNetCore.Identity - 如何为新用户设置 LockoutEnabled = false

c# - 使用 startup.cs 中分配的委托(delegate)处理 OnTokenValidated 时出现问题

java - 指定子类的注入(inject)

java - @Autowired 与 XML

c# - 面部形状分割

c# - .NET 中事件签名的代码友好版本

c# - 未找到站点核心 IComputedIndex 字段类/未运行

html - 使用提交按钮传递附加数据

c# - 在 Windows 服务中托管 ASP.NET 5 Web 应用程序