2 votes

Autofac dans une solution multi-projets

J'utilise Autofac comme système d'injection de dépendances dans une solution C# qui englobe plusieurs bibliothèques de classes et plusieurs exécutables. J'utilise des modules pour configurer Autofac, mais cela me laisse toujours le problème de la construction du conteneur DI, qui varie selon l'exécutable pour lequel je le compose.

J'ai essayé d'utiliser RegisterAssemblyModules d'Autofac, mais vous devez lui donner une liste d'assemblages à analyser, et jusqu'à ce qu'un certain type d'assemblage dans une bibliothèque de classe soit utilisé, l'assemblage n'est pas chargé, et donc pas disponible pour l'analyse.

Certaines personnes recommandent de charger chaque assemblage du répertoire bin qui pourrait contenir une définition de module Autofac. Mais cela semble poser le risque qu'un assemblage non désiré se glisse dans l'action.

J'ai donc créé cette classe statique, qui est définie dans une bibliothèque de classes communes :

public static class Container
{
    private static IContainer _instance;
    private static Dictionary<string, Assembly> _moduleAssemblies = new Dictionary<string, Assembly>();

    public static void RegisterAutofacModuleAssembly<T>()
        where T : class
    {
        var assembly = typeof(T).Assembly;

        if( !_moduleAssemblies.ContainsKey( assembly.FullName ) )
            _moduleAssemblies.Add( assembly.FullName, assembly );
    }

    public static IContainer Instance
    {
        get
        {
            if( _instance == null )
            {
                var builder = new ContainerBuilder();

                builder.RegisterAssemblyModules( _moduleAssemblies.Select( ma => ma.Value ).ToArray() );

                _instance = builder.Build();
            }

            return _instance;
        }
    }
}

Vous l'utilisez en incluant des lignes comme celle-ci dans le code de démarrage d'une application :

public static void Main(string[] args)
{
  AutoFacRegistrar.Container.RegisterAutofacModuleAssembly<ScannerApp>(); 
  AutoFacRegistrar.Container.RegisterAutofacModuleAssembly<AppConfiguration>();

S'agit-il d'une solution raisonnable ? S'il en existe une meilleure, plus souple, j'aimerais la connaître.

Question en IOptions<> Système de fixation

En mettant en œuvre la suggestion de @Nightowl888, j'ai rencontré un problème avec la configuration Microsoft IOptions<> système. Voici comment j'essaie de configurer Autofac pour résoudre les objets AppConfiguration :

protected override void Load( ContainerBuilder builder )
{
    base.Load( builder );

    var config = new ConfigurationBuilder()
        .AddJsonFile( AppConfiguration.WebJobsConfigFile, false )
        .AddUserSecrets<ConfigurationModule>()
        .AddEnvironmentVariables()
        .Build();

    builder.Register<AppConfiguration>( ( c, p ) =>
        {
            var retVal = new AppConfiguration( c.Resolve<ILogger>() );

            config.Bind( retVal );

            return retVal;

        } )
        .SingleInstance();
}

Le problème se produit dans l'appel à Bind(). En parcourant et en analysant les informations de configuration, il s'attend à créer divers objets par le biais de constructeurs sans paramètres... ce qui rend difficile l'utilisation de l'injection des constructeurs.

Si je ne peux pas utiliser l'injection de constructeur, je dois être capable de résoudre contre le conteneur DI dans le code du constructeur. Je ne vois pas comment je peux définir un assemblage de bibliothèque qui n'intègre pas la sémantique de résolution d'un conteneur DI particulier.

Réflexions ? Autre que "abandonner le IOptions<> système", que j'ai envisagé, mais il offre un certain nombre d'avantages que j'aimerais conserver.

2voto

NightOwl888 Points 4622

Chaque application exécutable doit avoir son propre configuration DI unique. Bibliothèques y cadres doivent être construits de manière à être conviviaux, mais sans faire référence à un conteneur DI.

Une racine de composition est le configuration . Le partager entre les applications est similaire au partage d'un .config entre les applications - c'est-à-dire que cela ne se fait pas habituellement. Voir Composition Réutilisation des racines .

Si vous devez utiliser des modules autofac, ils doivent faire partie de l'application qui les utilise, et non être inclus dans l'assemblage avec les composants qui sont composés. Bien qu'il puisse sembler que vous gagnez quelque chose en n'ayant pas à répéter le code de configuration dans chaque application, le principal problème est que cela signifie que votre application a perdu l'un des principaux avantages de l'ID - c'est-à-dire qu'elle ne peut pas fournir un code de configuration à l'utilisateur. alternative de tout composant donné. L'intérêt de rendre une bibliothèque faiblement couplée est de permettre à l'application qui héberge les composants de décider en dernier ressort de la manière dont elle sera couplée.

Ma bête noire : Notez également que le nombre de projets ou de solutions que vous avez n'a absolument rien à voir avec le comportement d'exécution d'une application (comme la façon dont elle est composée). Les projets et les solutions sont un moyen d'organiser le code avant qu'il ne soit compilé - une fois le code compilé, il n'y a plus de concept de "projet" ou de "solution", il ne reste que des "assemblages" qui peuvent dépendre d'autres "assemblages". Pour chaque application, on se retrouve avec un exécutable et 0 ou plusieurs ensembles dépendants. Le Root de composition ne doit exister que dans l'assemblage exécutable.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X