.NET Core DI, зарегистрируйте реализацию по умолчанию для пакета - PullRequest
1 голос
/ 22 мая 2019

Как можно зарегистрировать реализацию по умолчанию, используя контейнер IoC для .NET Core, а также предоставить способ переопределить существующую реализацию?

Например, я мог бы захотеть создать пакет, который обеспечивает реализацию по умолчанию для некоторого сервиса.

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 { }
}

Ответы [ 2 ]

3 голосов
/ 22 мая 2019

Если ваш пакет содержит класс, который настраивает 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, вы можете разрешить ему указывать только тип службы, а ваша конфигурация определяет, как она будет зарегистрирована (singleton, transient и т. Д.)

Это также полезный шаблон, когда библиотека зависит от значений конфигурации, таких как строки подключения, которые должны быть предоставлены потребителем. Вы можете сделать их обязательными аргументами для построения опций, а затем потребовать опций для построения установщика, или просто сделать их обязательными аргументами в установщике. Теперь невозможно установить пакет без необходимых значений конфигурации.

2 голосов
/ 22 мая 2019

Встроенный контейнер .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-контейнера, как описано Марком Симманом в его статье DI-Friendly Library .

...