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

9

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

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

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

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

источник

Ответы:

10

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

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

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

    return services;
}

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

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

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

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

совать
источник
3

Создайте пользовательский атрибут (называемый 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класс, чтобы он поддерживал все области, такие как синглтон и т. Д. Этот пример показан только для переходного времени жизни.

Наслаждаться!!!

Дилхан Джаяфилаке
источник
0

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

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

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

Shymep
источник