2013-01-23 14 views
5

Autofac का उपयोग करना, मैं संपत्ति इंजेक्शन का उपयोग कर, निम्नलिखित कोड का उपयोग कर एक अंतरफलक के खिलाफ हल करने एक वर्ग रजिस्टर कर सकते हैं:कैसे एक निर्माता पैरामीटर के रूप में निर्भरता नाम सुई

builder.RegisterType<Log4NetAdapter>() 
     .As<ILogger>() 
     .PropertiesAutowired() 
     .InstancePerDependency(); 

लेकिन, मेरा Log4NetAdapter वर्ग एक निर्माता पैरामीटर है जिसके लिए कॉलिंग क्लास का नाम आवश्यक है। इस तरह, मैं कॉलिंग क्लास के नाम के आधार पर ईवेंट लॉग कर सकता हूं।

public class Log4NetAdapter : ILogger 
{ 
    private readonly ILog _logger; 

    public Log4NetAdapter(string logName) 
    { 
     _logger = LogManager.GetLogger(logName); 
    } 

    ... 
} 

मैं नाम (अर्थात typeof(dependency).Name) संपत्ति इंजेक्शन वर्ग 'निर्माता में निर्भरता के देखते हुए कि प्रत्येक निर्भरता का अपना Log4NetAdapter उदाहरण होगा कैसे इंजेक्षन कर सकते हैं?

+0

जब आप लकड़हारा यह अक्सर आवेदन में बहुत अधिक प्रवेश कर का एक संकेत है में वर्ग के नाम की जरूरत है। अपने आवेदन के डिजाइन पर एक अच्छा नज़र डालने पर विचार करें। [यह SO उत्तर विस्तार से चला जाता है] (http://stackoverflow.com/a/9915056/264697) बहुत अधिक लॉगिंग के बारे में। – Steven

+1

@Steven यह एक अच्छा लेख है और हां, मुझे लॉग इन करने के तरीके को संशोधित करने की संभावना है। – Digbyswift

उत्तर

3

अद्यतन: बिल्डिंग LogInjectionModule नमूना और how Autofac does property injection पर, मैं दोनों निर्माता और संपत्ति इंजेक्शन करने के लिए मॉड्यूल विस्तार किया है।

नोट: मैंने LogManager को OnComponentPreparing में घोषित प्रकार का उपयोग करने के लिए टाइप किया है। यह उदाहरण देता है Resolve<Func<Service>> सही लॉग प्रकार का उपयोग करें।

using System.Linq; 
    using log4net; 

    public class LogInjectionModule : Module 
    { 
     protected override void AttachToComponentRegistration(IComponentRegistry registry, IComponentRegistration registration) 
     { 
      registration.Preparing += OnComponentPreparing; 
      registration.Activating += OnComponentActivating; 
     } 

     private static void OnComponentActivating(object sender, ActivatingEventArgs<object> e) 
     { 
      InjectLogProperties(e.Context, e.Instance, false); 
     } 

     private static void OnComponentPreparing(object sender, PreparingEventArgs e) 
     { 
      e.Parameters = e.Parameters.Union(new[] 
       { 
        new ResolvedParameter(
         (p, i) => p.ParameterType == typeof(ILog), 
         (p, i) => LogManager.GetLogger(p.Member.DeclaringType)) 
       }); 
     } 

     private static void InjectLogProperties(IComponentContext context, object instance, bool overrideSetValues) 
     { 
      if (context == null) throw new ArgumentNullException("context"); 
      if (instance == null) throw new ArgumentNullException("instance"); 

      var instanceType = instance.GetType(); 
      var properties = instanceType 
       .GetProperties(BindingFlags.Public | BindingFlags.Instance) 
       .Where(pi => pi.CanWrite && pi.PropertyType == typeof(ILog)); 

      foreach (var property in properties) 
      { 
       if (property.GetIndexParameters().Length != 0) 
        continue; 

       var accessors = property.GetAccessors(false); 
       if (accessors.Length == 1 && accessors[0].ReturnType != typeof(void)) 
        continue; 

       if (!overrideSetValues && 
        accessors.Length == 2 && 
        (property.GetValue(instance, null) != null)) 
        continue; 

       ILog propertyValue = LogManager.GetLogger(instanceType); 
       property.SetValue(instance, propertyValue, null); 
      } 
     } 
    } 

कैसे मॉड्यूल का उपयोग करने के लिए पर, यहाँ एक नमूना है:

public class Service 
{ 
    public Service(ILog log) { ... } 
} 

var cb = new ContainerBuilder(); 
cb.RegisterModule<LogInjectionModule>(); 
cb.RegisterType<Service>(); 
var c = cb.Build(); 

var service = c.Resolve<Service>(); 
+0

यदि लिंक मर जाता है तो आप इस जवाब को मृत होने से बचने के लिए लिंक से कुछ विवरण प्रदान करना चाह सकते हैं। – Guvante

+0

@ पीटर मुझे लगता है कि लिंक पर समाधान केवल कंस्ट्रक्टर इंजेक्शन से संबंधित है, न कि संपत्ति इंजेक्शन। – Digbyswift

+0

@Digbyswift - यह सही है। यह आपके प्रश्न से स्पष्ट नहीं था कि आईएलओजी प्राप्तकर्ता को संपत्ति इंजेक्शन की आवश्यकता है। सीटीओ इंजेक्शन का उपयोग न करने का कोई कारण नहीं है? –

1

आप का उपयोग केवल ILog नाम से प्रभावी ढंग से हल करने के लिए करते हैं, तो क्यों न केवल ILog इंजेक्ट करें?

public class Log4NetAdapter : ILogger 
{ 
    private readonly ILog _logger; 

    public Log4NetAdapter(ILog logger) 
    { 
     _logger = logger; 
    } 

    ... 
} 

ठीक है, तो अब मैं सिर्फ समस्या थोड़ा स्थानांतरित कर दिया है, लेकिन मैं भी इस कम अन्य वर्गों के लिए युग्मित, अर्थात् LogManager कर दिया है।

तो अगर मैं एकता उपयोग कर रहा था, मैं तो यह मैं सही लकड़हारा प्राप्त सुनिश्चित करने के लिए करना होगा:

var childContainer = container.CreateChildContainer(); 
childContainer.RegisterInstance<ILog>(LogManager.GetLogger(logName)); 
var adaptor = childContainer.Resolve<Log4NetAdapter>(); 

बच्चे कंटेनर कि ILog के लिए किसी भी अन्य कोड हो रही पहुँच रोकता है। आप इसे जितना चाहें उतना ऊंचा कर सकते हैं, मुझे आपके कोड के बारे में और कुछ नहीं पता है।

+0

धन्यवाद, लेकिन आपका उत्तर मुझे नहीं बताता है कि मुझे 'लॉगनाम' पैरामीटर कहाँ से मिलता है - जब तक कि मुझे कुछ याद नहीं आया। साथ ही, यह विशेष रूप से एडाप्टर का उपयोग कर उदाहरण है जिसमें मुझे रूचि है, लेकिन मैं आपका पॉइंट देखता हूं। – Digbyswift

+0

किसी बिंदु पर आपको 'लॉगनाम' पता चलेगा, अगर नहीं, तो मैं आपकी मदद नहीं कर सकता, लेकिन यह बात है कि आपको इसे 'लॉग 4नेट एडाप्टर' को हल करने से पहले 'ILog' के रूप में पंजीकृत करना चाहिए, लेकिन मेरे पास कोई और कोड नहीं है आगे बढ़ने के लिए मैं आगे की सलाह नहीं दे सकता। ऐसा लगता है कि पीटर से हालांकि आपको समाधान मिला है। – weston

संबंधित मुद्दे