Existe uma maneira robusta de registrar dependências no ASP.NET Core 3.1, além de adicionar tudo à classe Startup?

9

Eu tenho um projeto ASP.NET Core 3.1. Normalmente, registro qualquer dependência usando o ConfigureServices()método na Startup.csclasse

Mas, tenho que registrar muitas dependências e a ConfigureServices()aparência é enorme! Eu sei que provavelmente posso criar um método de extensão de um método estático e chamá-lo da classe ConfigureService () `, mas me pergunto se existe uma maneira melhor.

Se houver uma maneira de registrar dependências no contêiner de IoC sem precisar defini-las uma por vez como esta

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

fonte

Respostas:

10

O agrupamento de dependências relacionadas em métodos de extensão personalizados é uma maneira muito comum de fazer isso. O ASP.NET Core já faz isso para muitos serviços internos, e você pode facilmente expandir além disso e configurá-los da maneira que você precisa para seu aplicativo. Por exemplo, para configurar autenticação e autorização:

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

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

    return services;
}

Você pode fazer o mesmo pelos serviços específicos do aplicativo e agrupá-los logicamente em métodos de extensão separados.

Se você tiver muitos registros de serviços muito semelhantes, também poderá empregar um registro baseado em convenções, por exemplo, usando o Scrutor . Por exemplo, isso registra todos os serviços em um determinado espaço de nome como transitório para sua respectiva interface:

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

O Scrutor permite que regras muito complexas varram serviços, portanto, se seus serviços seguirem algum padrão, você provavelmente poderá criar uma regra para isso.

cutucar
fonte
3

Crie um atributo personalizado (chamado AutoBindAttribute)

public class AutoBindAttribute : Attribute
{
}

Use-o como abaixo (Decore todas as implementações que você deseja vincular automaticamente ao [AutroBind])

public interface IMyClass {}

[AutoBind]
public class MyClass : IMyClass {}

Agora crie um método de extensão para 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();
    }
}

Agora chame-o em Startup.cs

public class Startup
{

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

}

Nota: Você pode melhorar a ServiceCollectionExtentionsclasse para oferecer suporte a todos os escopos, como singleton, etc. Este exemplo mostra apenas a vida útil transitória.

Aproveitar!!!

Dilhan Jayathilake
fonte
0

Além do que foi mencionado.

Pessoalmente, gosto de ter uma classe separada registrando dependências por cada assembly. Isso adiciona mais controle sobre o uso de classes na camada correta e permite torná-lasinternal qual IMO é boa.

A decisão de usar scanou não mecanismos depende de você. Algumas estruturas fornecem isso por padrão. O agrupamento de dependências semelhantes em um conjunto de classes / métodos, por sua vez, deve ajudar a manter a resolução da lógica em um local consistente para qualquer alteração. Você pode combinar as duas abordagens.

Shymep
fonte