Existe-t-il un moyen robuste d'enregistrer les dépendances dans ASP.NET Core 3.1 en plus de tout ajouter à la classe de démarrage?

9

J'ai un projet ASP.NET Core 3.1. En règle générale, j'enregistre toute dépendance à l'aide de la ConfigureServices()méthode dans la Startup.csclasse.

Mais, je me retrouve à enregistrer beaucoup de dépendances et le ConfigureServices()look est énorme! Je sais que je peux probablement créer une méthode d'extension d'une méthode statique et l'appeler à partir de la classe ConfigureService () `, mais je me demande s'il y a une meilleure façon.

S'il existe un moyen d'enregistrer les dépendances dans le conteneur IoC sans avoir à les définir une à la fois comme ceci

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

la source

Réponses:

10

Le regroupement des dépendances liées dans des méthodes d'extension personnalisées est un moyen très courant de procéder. ASP.NET Core le fait déjà pour de nombreux services internes, et vous pouvez facilement développer en plus de cela et les configurer comme vous le souhaitez pour votre application. Par exemple, pour configurer l'authentification et l'autorisation:

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

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

    return services;
}

Vous pouvez faire de même pour vos services spécifiques à une application et les regrouper logiquement dans des méthodes d'extension distinctes.

Si vous avez de nombreux enregistrements de services très similaires, vous pouvez également utiliser un enregistrement basé sur une convention, par exemple en utilisant Scrutor . Par exemple, cela enregistre tous les services dans un certain espace de noms comme transitoires pour leur interface respective:

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

Scrutor permet à des règles très complexes de rechercher des services, donc si vos services suivent un certain modèle, vous pourrez probablement trouver une règle pour cela.

poussée
la source
3

Créez un attribut personnalisé (appelé AutoBindAttribute)

public class AutoBindAttribute : Attribute
{
}

Utilisez-le comme ci-dessous (Décorez toutes les implémentations que vous souhaitez lier automatiquement avec [AutroBind])

public interface IMyClass {}

[AutoBind]
public class MyClass : IMyClass {}

Créez maintenant une méthode d'extension pour 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();
    }
}

Appelez-le maintenant dans Startup.cs

public class Startup
{

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

}

Remarque: Vous pouvez améliorer la ServiceCollectionExtentionsclasse pour prendre en charge toutes les étendues telles que singleton, etc. Cet exemple ne montre que pour la durée de vie transitoire.

Prendre plaisir!!!

Dilhan Jayathilake
la source
0

En plus de ce qui a été mentionné.

Personnellement, j'aime avoir une classe d'enregistrement des dépendances distincte pour chaque assembly. Cela ajoute plus de contrôle sur l'utilisation des classes sur la bonne couche et permet de les rendreinternal IMO bonnes.

Que vous scanutilisiez ou non des mécanismes dépend de vous. Certains frameworks donnent cela par défaut. Le regroupement de dépendances similaires dans un ensemble de classes / méthodes, à son tour, devrait aider à garder la logique de résolution à un endroit cohérent pour tout changement. Vous pouvez combiner les deux approches.

Shymep
la source