2013-03-24 12 views
22

W aplikacji konsolowej używam Log4Net iw metodzie głównej uzyskuję obiekt rejestratora. Teraz chciałbym uczynić ten obiekt logu dostępnym we wszystkich moich klasach, pozwalając wszystkim klasom dziedziczyć z klasy BaseClass, która ma właściwość ILog i powinna być ustawiona przez Injection własność, a nie Constructor Injection.Jak korzystać z funkcji Property Injection z AutoFac?

Używam kontenera IoC AutoFac, jak wprowadzić mój obiekt logu do właściwości Log mojej klasy?

Jaki jest najlepszy/najprostszy sposób, aby to osiągnąć?

Czy istnieje sposób automatycznego rozwiązywania typów?

Poniżej jest mój wniosek 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"); 
     } 
    } 
} 
+1

Można również utworzyć statyczną instancję rejestratora w każdej z klas. W ten sposób każdy rejestrator automatycznie będzie miał nazwę klasy, gdzie została zdefiniowana. – alex

+2

Usuń "statyczny" z Ilog w 'produkcie' –

+0

Próbowałem również z instancją, ale nie pomogłem. –

Odpowiedz

18

Zastosowanie Property Injection:

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

builder.RegisterType<CustomClass>() 
     .PropertiesAutowired(); 
+0

dzięki, ale co tu/gdzie jest klasa Log? Po prostu mam interfejs ILog, który myślę. Obiekt ILog jest pobierany z LogManager.GetLogger ("LoggerName"); –

+0

@TheLight: Edytowałem swoją odpowiedź, ponownie :) –

+0

Dobrze, dzięki, mogę teraz zobaczyć obiekt dziennika z kontenera przez container.Resolve (). ale w jaki sposób mogę poprosić AutoFac, aby automatycznie usunął ILog, gdziekolwiek go zobaczy? Nie rozwiązuje go automatycznie i zgłasza wyjątek, kiedy uzyskuję dostęp do właściwości Log w mojej CustomClass. –

9

wtrysk nieruchomości działa na Properties a nie dla Fields. W twojej klasie Log jest polem, a nie własnością, a więc nigdy nie zostanie rozwiązany przez Autofac.

18

Moim zdaniem, rozwiązanie Ninject created jest o wiele ładniejsze niż propertyinjection w Autofac. Dlatego stworzyłem aa atrybut niestandardowy, który jest aspekt PostSharp który automatycznie wstrzykuje moje klasy:

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

My aspekt: ​​

[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(); 
     } 
    } 
} 

znam odpowiedź na pytanie jest już wydane, ale myślałem, że to był naprawdę fajny sposób rozwiązywania automatycznego wtrysku własności w Autofac. Może przyda się komuś w przyszłości.

+1

upowszechnianie kreatywności :) thx –

+0

Tak, przydatne dla mnie :) –

+0

Czy masz rozwiązanie bez postsharp? –

2

Nie chciałem używać funkcji postsharp, więc zrobiłem szybkie rozwiązanie, ale nie wstrzykuje się automatycznie. Jestem nowy w firmie Autofac i powinno być możliwe korzystanie z tego rozwiązania.

[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); 
     } 
    } 
} 

Użyj go z tej rozmowy:

AutofactResolver.InjectProperties(sourceObject);