Есть ли надежный способ регистрации зависимостей в ASP. NET Core 3.1 помимо добавления всего в класс запуска? - PullRequest
9 голосов
/ 20 февраля 2020

У меня есть ASP. NET Core 3.1 проект. Обычно я регистрирую любую зависимость, используя метод ConfigureServices() в классе Startup.cs.

Но мне приходится регистрировать множество зависимостей, и ConfigureServices() выглядит огромно! Я знаю, что могу, вероятно, создать метод расширения для метода stati c и вызвать его из класса ConfigureService () `, но мне интересно, есть ли лучший способ.

Если есть способ регистрации зависимостей в контейнер Io C без необходимости определять их по одному, например:

services.AddScoped<Interface, Class>();
.... 200 lines later
services.AddScoped<ISettings, Settings>()

Ответы [ 3 ]

10 голосов
/ 20 февраля 2020

Группировка связанных зависимостей в пользовательские методы расширения - очень распространенный способ сделать это. ASP. NET Core уже делает это для многих внутренних сервисов, и вы можете легко расширить их и настроить так, как вам нужно для вашего приложения. Например, чтобы настроить аутентификацию и авторизацию:

public IServiceCollection AddSecurity(this IServiceCollection services)
{
    services.AddAuthentication()
        .AddCookie();

    service.AddAuthorization(options =>
    {
        options.DefaultPolicy = …;
    });

    return services;
}

Вы можете сделать то же самое для сервисов c, определенных для приложения, и логически сгруппировать их в отдельные методы расширения.

Если у вас есть Многие сервисные регистрации очень похожи, вы также можете использовать регистрацию на основе конвенций, например, используя Scrutor . Например, при этом все службы в определенном пространстве имен регистрируются как переходные для их соответствующего интерфейса:

services.Scan(scan => scan
    .FromAssemblyOf<Startup>()
        .AddClasses(c => c.InNamespaces("MyApp.Services"))
            .AsImplementedInterfaces()
            .WithTransientLifetime()
);

Scrutor позволяет очень сложным правилам искать службы, поэтому, если ваши службы следуют некоторым шаблон, вы, вероятно, сможете придумать правило для этого.

3 голосов
/ 20 февраля 2020

Создайте пользовательский атрибут (называемый AutoBindAttribute)

public class AutoBindAttribute : Attribute
{
}

Используйте его, как показано ниже (Украсьте все реализации, которые вы хотите автоматически связать, с помощью [AutroBind])

public interface IMyClass {}

[AutoBind]
public class MyClass : IMyClass {}

Сейчас создайте метод расширения для IServiceCollection

public class ServiceCollectionExtentions
{
    public static void AutoBind(this IServiceCollection source, params Assembly[] assemblies)
    {
       source.Scan(scan => scan.FromAssemblies(assemblies)
        .AddClasses(classes => classes.WithAttribute<AutoBindAttribute>())
        .AsImplementedInterfaces()
        .WithTransientLifetime();
    }
}

Теперь вызовите его в Startup.cs

public class Startup
{

    public void ConfigureServices(IServiceCollection services)
    {
        services.AutoBind(typeof(Startup).Assembly);
    }

}

Примечание. Вы можете улучшить класс ServiceCollectionExtentions для поддержки всех областей, таких как singleton, et c. Этот пример показывает только для переходного времени жизни.

Наслаждайтесь !!!

0 голосов
/ 20 февраля 2020

В дополнение к тому, что было упомянуто.

Лично мне нравится иметь отдельный класс, регистрирующий зависимости для каждой сборки. Это добавляет больше контроля над использованием классов на нужном уровне и позволяет сделать их internal, что хорошо для ИМО.

Использовать ли механизмы scan или нет - решать вам. Некоторые рамки дают это по умолчанию. Группировка схожих зависимостей в наборе классов / методов, в свою очередь, должна помочь сохранить разрешение логики c в согласованном месте для любых изменений. Вы можете комбинировать оба подхода.

...