web-dev-qa-db-fra.com

Comment utiliser Property Injection avec AutoFac?

Dans une application console, j'utilise Log4Net et dans la méthode Main, j'obtiens l'objet enregistreur. Maintenant, j'aimerais rendre cet objet journal disponible dans toutes mes classes en laissant toutes les classes hériter d'une BaseClass qui possède une propriété ILog et qui est supposée être définie par Property Injection plutôt que par Constructor Injection.

J'utilise un conteneur AutoFac IoC, comment injecter mon objet log dans la propriété Log de chaque classe?

Quelle est la meilleure façon/la plus simple d'y parvenir?

Est-il possible de résoudre automatiquement les types?

Ci-dessous, mon application de test:

namespace ConsoleApplication1
{
    class Program
    {
        static ILog Log;
        static IContainer Container;

        static void Main(string[] args)
        {                
           InitializeLogger();

           InitializeAutoFac();

            // the below works but could it be done automatically (without specifying the name of each class)?
           Product.Log = Container.Resolve<ILog>();

           // tried below but didn't inject ILog object into the Product
           Container.Resolve<Product>();

           RunTest();

            Console.ReadLine();
        }

        private static void RunTest()
        {
            var product = new Product();
            product.Do();
        }

        private static void InitializeAutoFac()
        {
            var builder = new ContainerBuilder();

            builder.Register(c => Log).As<ILog>();

            builder.RegisterType<Product>().PropertiesAutowired();

            Container = builder.Build();            
        }

        private static void InitializeLogger()
        {
            log4net.Config.XmlConfigurator.Configure();

            Log = LogManager.GetLogger("LoggerName");
        }
    }

    public class Product
    {
        public static ILog Log { get; set; }

        public void Do()
        {
            // this throws exception because Log is not set   
            Log.Debug("some Debug");  
        }
    }
}
25
The Light

Utilisation Injection de propriété :

builder.Register(c => LogManager.GetLogger("LoggerName"))
       .As<ILog>();

builder.RegisterType<CustomClass>()
       .PropertiesAutowired();
21
cuongle

À mon avis, la solution Ninject created est beaucoup plus agréable que le propertyinjection dans Autofac. J'ai donc créé un attribut personnalisé qui est un aspect postsharp qui injecte automatiquement mes classes:

[AutofacResolve]
public IStorageManager StorageManager { get; set; }

Mon aspect:

[Serializable]
[AttributeUsage(AttributeTargets.Property, AllowMultiple = false)]
public class AutofacResolveAttribute : LocationInterceptionAspect
{
    public override void OnGetValue(LocationInterceptionArgs args)
    {
        args.ProceedGetValue();

        if (!args.Location.LocationType.IsInterface) return;

        if ( args.Value != null )
        {
           args.Value = DependencyResolver.Current.GetService(args.Location.LocationType);
           args.ProceedSetValue();
        }
    }
}

Je sais que la réponse à la question est déjà donnée, mais j’ai pensé que c’était une façon très élégante de résoudre l’injection automatique de propriétés dans Autofac. Peut-être que ça va être utile à quelqu'un dans le futur. 

21
ydd1987

L'injection de propriété fonctionne pour Propriétés et pas pour Champs . Dans votre classe, Log est un champ et non une propriété. Il ne sera donc jamais résolu par la fonction Autofac.

11
Naresh Mittal

Je ne voulais pas utiliser postsharp, alors j'ai proposé une solution rapide, mais elle ne s'injecte pas automatiquement. Je suis nouveau sur Autofac et il devrait être possible de développer cette solution.

[Serializable]
[AttributeUsage(AttributeTargets.Property)]
public class AutofacResolveAttribute : Attribute
{
}

public class AutofactResolver
{
    /// <summary>
    /// Injecting objects into properties marked with "AutofacResolve"
    /// </summary>
    /// <param name="obj">Source object</param>
    public static void InjectProperties(object obj)
    {
        var propertiesToInject = obj.GetType().GetProperties()
             .Where(x => x.CustomAttributes.Any(y => y.AttributeType.Name == nameof(AutofacResolveAttribute))).ToList();

        foreach (var property in propertiesToInject)
        {
            var objectToInject = Autofact.SharedContainer.Resolve(property.PropertyType);
            property.SetValue(obj, objectToInject, null);
        }
    }
}

Utilisez-le avec cet appel:

AutofactResolver.InjectProperties(sourceObject);
3
Morten Holmgaard

Utilisez Propriété Injection (En plus de @cuongle answer).

Option 1:

builder.Register(c => LogManager.GetLogger("LoggerName")).As<ILog>();

builder.RegisterType<Product>()
        .WithProperty("Log", LogManager.GetLogger("LoggerName"));

Option 2:

Ou vous pouvez ajouter une méthode SetLog à la classe Product:

public class Product
{
    public static ILog Log { get; set; }
    public SetLog(Log log)
    {
        this.Log = log;
    }
}

Ainsi, vous n'aurez pas à appeler LogManager.GetLogger("LoggerName") deux fois mais à utiliser le contexte du générateur afin de résoudre la Log.

builder.Register(c => LogManager.GetLogger("LoggerName")).As<ILog>();

builder.Register(c => 
    var product = new Product();
    product.SetLog(c.Resolve<Log>());
    return product;
);

Option 3:

Utilisez le OnActvated :

L'événement OnActivated est déclenché une fois qu'un composant est entièrement construit . Ici, vous pouvez effectuer des tâches au niveau de l’application qui dépendent du fichier composant étant entièrement construit - ceux-ci devraient être rares.

builder.RegisterType<Product>()
    .OnActivated((IActivatedEventArgs<Log> e) =>
    {
        var product = e.Context.Resolve<Parent>();
        e.Instance.SetParent(product);
    });

Ces options donnent plus de contrôle et vous n'aurez pas à vous soucier du commentaire @steven:

Ce qui fait peur avec PropertiesAutowired, c’est que c’est le cas injection de propriété implicite, ce qui signifie que toute solution insoluble les dépendances seront ignorées. Cela facilite la configuration manquée erreurs et peuvent entraîner une application qui échoue au moment de l'exécution

0
Shahar Shokrani