Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/277.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/asp.net-core/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# .NET Core DI,为包注册默认实现_C#_Asp.net Core_Dependency Injection_.net Core_Inversion Of Control - Fatal编程技术网

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

C# .NET Core DI,为包注册默认实现,c#,asp.net-core,dependency-injection,.net-core,inversion-of-control,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 { Serv

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

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

namesapce Package 
{
    public interface ISomeService { }

    public class Default : ISomeService { }
}
然后在同一个包中使用此服务

namesapce Package 
{
    public class Service 
    {
        Service(ISomeService service) { }
    }
}
如何注册
ISomeService
默认实现

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

namespace Project 
{
    public class Override : ISomeService { }
}

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

//包注册(包的一部分)
services.AddTransient();
//由应用程序开发人员覆盖(属于Startup.cs的一部分)
services.AddTransient();

一定要考虑以不需要使用DI容器的方式构建包,正如Mark Seemann在其文章中所描述的。

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

//包注册(包的一部分)
services.AddTransient();
//由应用程序开发人员覆盖(属于Startup.cs的一部分)
services.AddTransient();

一定要考虑以不需要使用DI容器的方式构建包,如Mark Seemann在其文章中所述。

如果包中包含配置
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>();
    }
}
公共类MyPackageInstaller
{
私有只读MyPackageRegistrationOptions\u选项;
公共MyPackageInstaller(MyPackageRegistrationOptions=null)
{
_选项=选项;
}
public void安装(IServiceCollection服务)
{
if(_options?.FooServiceDescriptor!=null)
添加(_options.FooServiceDescriptor);
其他的
//这是您的默认实现
services.AddSingleton();
}
}
用法:

var services = new ServiceCollection();
var options = new MyPackageRegistrationOptions();
options.AddFooService(ServiceDescriptor.Singleton<IFooService, AlternateFooService>());
var installer = new MyPackageInstaller(options);
installer.Install(services);
var services=newservicecolection();
var options=新的MyPackageRegistrationOptions();
options.AddFooService(ServiceDescriptor.Singleton());
var安装程序=新的MyPackageInstaller(选项);
安装程序。安装(服务);
乍一看,要获得同样的结果,这似乎是一条漫长的道路。好处是它允许您更清楚地说明哪些服务应该或不应该被覆盖。这样,您感觉更像是在使用故意公开的配置选项,而不是戳包的内部

namesapce Package 
{
    public class Service 
    {
        Service(ISomeService service) { }
    }
}
您可以不允许使用者添加
服务描述符
,而只允许他们指定服务类型,并且您的配置决定如何注册服务(单例、瞬态等)


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

如果您的软件包包含配置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>();
    }
}
公共类MyPackageInstaller
{
私有只读MyPackageRegistrationOptions\u选项;
公共MyPackageInstaller(MyPackageRegistrationOptions=null)
{
_选项=选项;
}
public void安装(IServiceCollection服务)
{
if(_options?.FooServiceDescriptor!=null)
添加(_options.FooServiceDescriptor);
其他的
//这是您的默认实现
services.AddSingleton();
}
}
用法:

var services = new ServiceCollection();
var options = new MyPackageRegistrationOptions();
options.AddFooService(ServiceDescriptor.Singleton<IFooService, AlternateFooService>());
var installer = new MyPackageInstaller(options);
installer.Install(services);
var services=newservicecolection();
var options=新的MyPackageRegistrationOptions();
options.AddFooService(ServiceDescriptor.Singleton());
var安装程序=新的MyPackageInstaller(选项);
安装程序。安装(服务);
乍一看,要获得同样的结果,这似乎是一条漫长的道路。好处是它允许您更清楚地说明哪些服务应该或不应该被覆盖。这样,您感觉更像是在使用故意公开的配置选项,而不是戳包的内部

namesapce Package 
{
    public class Service 
    {
        Service(ISomeService service) { }
    }
}
您可以不允许使用者添加
服务描述符
,而只允许他们指定服务类型,并且您的配置决定如何注册服务(单例、瞬态等)

当库依赖于诸如连接字符串之类的配置值时,这也是一种有用的模式