Czy istnieje solidny sposób rejestrowania zależności w programie ASP.NET Core 3.1 oprócz dodawania wszystkiego do klasy Autostart?

9

Mam projekt ASP.NET Core 3.1. Zazwyczaj rejestruję dowolną zależność za pomocą ConfigureServices()metody w Startup.csklasie.

Ale muszę zarejestrować wiele zależności i ConfigureServices()wygląda to olbrzymie! Wiem, że prawdopodobnie mogę utworzyć metodę rozszerzenia metody statycznej i wywołać ją z klasy ConfigureService () `, ale zastanawiam się, czy istnieje lepszy sposób.

Jeśli istnieje sposób na zarejestrowanie zależności w kontenerze IoC bez konieczności definiowania ich pojedynczo w ten sposób

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

źródło

Odpowiedzi:

10

Grupowanie powiązanych zależności w niestandardowe metody rozszerzeń jest bardzo powszechnym sposobem na to. Program ASP.NET Core już to robi w przypadku wielu usług wewnętrznych, a ponadto można je łatwo rozbudować i ustawić tak, jak potrzebujesz dla swojej aplikacji. Na przykład, aby skonfigurować uwierzytelnianie i autoryzację:

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

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

    return services;
}

To samo możesz zrobić dla usług specyficznych dla aplikacji i pogrupować je logicznie w osobnych metodach rozszerzenia.

Jeśli masz wiele bardzo podobnych rejestracji usług, możesz także zastosować rejestrację opartą na konwencjach, np. Za pomocą Scrutora . Na przykład rejestruje wszystkie usługi w określonej przestrzeni nazw jako przejściowe dla ich odpowiedniego interfejsu:

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

Scrutor zezwala na bardzo złożone reguły skanowania w poszukiwaniu usług, więc jeśli twoje usługi są zgodne z pewnym wzorcem, prawdopodobnie będziesz w stanie wymyślić taką regułę.

szturchać
źródło
3

Utwórz niestandardowy atrybut (o nazwie AutoBindAttribute)

public class AutoBindAttribute : Attribute
{
}

Użyj go jak poniżej (Udekoruj wszystkie implementacje, które chcesz automatycznie powiązać z [AutroBind])

public interface IMyClass {}

[AutoBind]
public class MyClass : IMyClass {}

Teraz utwórz metodę rozszerzenia dla 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();
    }
}

Teraz nazwij to w Startup.cs

public class Startup
{

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

}

Uwaga: Możesz ulepszyć ServiceCollectionExtentionsklasę, aby obsługiwała wszystkie zakresy, takie jak singleton itp. Ten przykład pokazuje tylko dla życia Transient.

Cieszyć się!!!

Dilhan Jayathilake
źródło
0

Oprócz tego, o czym wspomniano.

Osobiście lubię mieć osobne klasy rejestrujące zależności dla każdego zestawu. Daje to większą kontrolę nad korzystaniem z klas na właściwej warstwie i pozwala na ustalenie, internalktóra z nich jest dobra.

To, czy użyć scanmechanizmów, czy nie, zależy od Ciebie. Niektóre ramy dają to domyślnie. Z kolei grupowanie podobnych zależności w zestawie klas / metod powinno pomóc w rozwiązaniu logiki w spójnym miejscu dla wszelkich zmian. Możesz połączyć oba podejścia.

Shymep
źródło