2011-06-07 6 views
20

पर पास किया गया है मेरे पास एक इंटरफ़ेस है।सेवा के आधार पर इंटरफ़ेस को कैसे हल करें, जहां इसे

public interface ISomeInterface {...} 

और दो कार्यान्वयन (SomeImpl1 और SomeImpl2):

public class Service1 : IService1 
{ 
    public Service1(ISomeInterface someInterface) 
    { 
    } 
... 
} 

और

public class Service2 : IService2 
{ 
    public Service2(ISomeInterface someInterface) 
    { 
    } 
... 
} 
:

public class SomeImpl1 : ISomeInterface {...} 
public class SomeImpl2 : ISomeInterface {...} 

मैं भी दो सेवाओं जहाँ मैं (contructor के माध्यम से) ISomeInterface इंजेक्षन है

मैं ऑटो का उपयोग कर रहा हूँ मेरे आईओसी उपकरण के रूप में ऑफैक। सवाल। मैं ऑटोफैक पंजीकरण कैसे कॉन्फ़िगर कर सकता हूं ताकि कुछ Impl1 स्वचालित रूप से Service1 में इंजेक्शन दिया जा सके, और SomeImpl2 स्वचालित रूप से Service2 में इंजेक्शन दिया जाएगा।

धन्यवाद!

उत्तर

28

ऑटोफैक identification of services by name का समर्थन करता है। इसका उपयोग करके, आप अपने कार्यान्वयन को एक नाम से पंजीकृत कर सकते हैं (Named एक्सटेंशन विधि का उपयोग करके)। ResolveNamed एक्सटेंशन विधि का उपयोग करके आप उन्हें IServiceX पंजीकरण प्रतिनिधियों में नाम से हल कर सकते हैं। निम्नलिखित कोड यह दर्शाता है।

var cb = new ContainerBuilder(); 
cb.Register(c => new SomeImpl1()).Named<ISomeInterface>("impl1"); 
cb.Register(c => new SomeImpl2()).Named<ISomeInterface>("impl2"); 
cb.Register(c => new Service1(c.ResolveNamed<ISomeInterface>("impl1"))).As<IService1>(); 
cb.Register(c => new Service2(c.ResolveNamed<ISomeInterface>("impl2"))).As<IService2>(); 
var container = cb.Build(); 

var s1 = container.Resolve<IService1>();//Contains impl1 
var s2 = container.Resolve<IService2>();//Contains impl2 

RegisterType का उपयोग कर (के रूप में करने का विरोध किया Register)

आप WithParameter और ResolvedParameter के साथ संयोजन में RegisterType विस्तार विधि का उपयोग कर एक ही परिणाम प्राप्त कर सकते हैं वैकल्पिक। यह उपयोगी है निर्माता नामांकित पैरामीटर को भी ले जा अन्य गैर नाम वाले पैरामीटर है कि आप एक पंजीकरण प्रतिनिधि में निर्दिष्ट करने के लिए परवाह नहीं है लेता है, तो: क्या आप संपत्ति इंजेक्शन करने के लिए निर्माता इंजेक्शन से स्विच कर सकते हैं, और यदि

var cb = new ContainerBuilder(); 
cb.RegisterType<SomeImpl1>().Named<ISomeInterface>("impl1"); 
cb.RegisterType<SomeImpl2>().Named<ISomeInterface>("impl2"); 
cb.RegisterType<Service1>().As<IService1>().WithParameter(ResolvedParameter.ForNamed<ISomeInterface>("impl1")); 
cb.RegisterType<Service2>().As<IService2>().WithParameter(ResolvedParameter.ForNamed<ISomeInterface>("impl2")); 
var container = cb.Build(); 

var s1 = container.Resolve<IService1>();//Contains impl1 
var s2 = container.Resolve<IService2>();//Contains impl2 
+0

उत्तर के लिए धन्यवाद। यह बढ़िया काम करता है। लेकिन मेरे कुछ Impl1 और SomeImpl2 की कई अन्य सेवाओं पर निर्भरता है। मैं पंजीकरण के दौरान उन सभी को निर्दिष्ट नहीं करना चाहता हूं। पंजीकरण के दौरान एक उदाहरण बनाये बिना इसे हासिल करने का कोई तरीका है: नया कुछ Impl1()? –

+0

मेरा मतलब कुछ है: builder.RegisterType ()। ()। ([सेवा 1 के पहले पैरामीटर के लिए यहां "impl1" निर्दिष्ट कैसे करें?]); –

+0

मैंने जवाब अपडेट किया है कि 'रजिस्टर टाइप' के साथ इसे कैसे प्राप्त किया जाए। – bentayloruk

4

दोनों सेवाओं के एक ही आधार वर्ग से निकाले जाते हैं (या एक ही इंटरफ़ेस को लागू), आप निम्न कर सकते हैं:

builder.RegisterType<ServiceBase>().OnActivating(e => 
{ 
    var type = e.Instance.GetType(); 

    // get ISomeInterface based on instance type, i.e.: 
    ISomeInterface dependency = 
     e.Context.ResolveNamed<ISomeInterface>(type.Name); 

    e.Instance.SomeInterface = dependency; 
}); 

इसके लिए आपको आधार प्रकार (या इंटरफ़ेस) पर संपत्ति परिभाषित करने की जरूरत काम करने के लिए। यह समाधान बहुत लचीला है और यहां तक ​​कि इस तरह के माता-पिता प्रकार के आधार पर, एक सामान्य प्रकार इंजेक्शन लगाने के रूप में जटिल चीजों को करने के लिए आप की अनुमति होगी, के रूप में नीचे देखें जा सकता है:

    :

    builder.RegisterType<ServiceBase>().OnActivating(e => 
    { 
        var type = 
         typeof(GenericImpl<>).MakeGenericType(e.Instance.GetType()); 
    
        e.Instance.SomeInterface = (ISomeInterface)e.Context.Resolve(type); 
    }); 
    

    यह दृष्टिकोण कुछ कमियां है

  1. हमें संपत्ति इंजेक्शन की आवश्यकता है।
  2. हमें उस बेस प्रकार या इंटरफ़ेस की आवश्यकता है जिसमें वह संपत्ति हो।
  3. हमें इस प्रकार का निर्माण करने के लिए प्रतिबिंब की आवश्यकता है, जो प्रदर्शन पर प्रभाव डाल सकता है (कंटेनर के निर्माण के बजाय एक कुशल प्रतिनिधि) (हालांकि हम प्रकार को कैशिंग करके चीजों को गति देने में सक्षम हो सकते हैं)।

ऊपर की ओर, यह डिज़ाइन सरल है और लगभग किसी भी कंटेनर के लिए काम करता है।

2

चार ऐसा करने का वेरिएंट autofac documentation में वर्णित हैं:

विकल्प 1: को पुनः डिजाइन आपका इंटरफेस

जब आप एक स्थिति है जहाँ आप कि समान सेवाओं को लागू घटकों का एक समूह है में चलाने लेकिन उन्हें समान रूप से इलाज नहीं किया जा सकता है, यह आम तौर पर एक इंटरफ़ेस डिज़ाइन समस्या है।

किसी ऑब्जेक्ट उन्मुख विकास परिप्रेक्ष्य से, आप अपने ऑब्जेक्ट्स को लिस्कोव प्रतिस्थापन सिद्धांत का पालन करने और ब्रेक के पालन के लिए चाहते हैं।

कुछ इंटरफ़ेस रीडिज़ाइन करके, आपको " संदर्भ द्वारा निर्भरता" चुनने की आवश्यकता नहीं है - आप अलग-अलग प्रकारों का उपयोग करते हैं और ऑटो-वायरअप जादू को संकल्प के दौरान होने देते हैं।

यदि आपके पास अपने समाधान पर परिवर्तन को प्रभावित करने की क्षमता है, तो यह अनुशंसित विकल्प है।

विकल्प 2: पंजीकरण बदलें

आप मैन्युअल रूप से है कि रास्ते में लेने वाली घटक के साथ उचित प्रकार संबद्ध कर सकते हैं:

var builder = new ContainerBuilder(); 
builder.Register(ctx => new ShippingProcessor(new PostalServiceSender())); 
builder.Register(ctx => new CustomerNotifier(new EmailNotifier())); 
var container = builder.Build(); 

// Lambda registrations resolve based on the specific type, not the 
// ISender interface. 
builder.Register(ctx => new ShippingProcessor(ctx.Resolve<PostalServiceSender>())); 
builder.Register(ctx => new CustomerNotifier(ctx.Resolve<EmailNotifier>())); 
var container = builder.Build(); 

विकल्प 3: उपयोग बंद सेवाएं

builder.RegisterType<PostalServiceSender>() 
      .As<ISender>() 
      .Keyed<ISender>("order"); 
    builder.RegisterType<EmailNotifier>() 
      .As<ISender>() 
      .Keyed<ISender>("notification"); 

builder.RegisterType<ShippingProcessor>() 
      .WithParameter(
      new ResolvedParameter(
       (pi, ctx) => pi.ParameterType == typeof(ISender), 
       (pi, ctx) => ctx.ResolveKeyed<ISender>("order"))); 
    builder.RegisterType<CustomerNotifier>(); 
      .WithParameter(
      new ResolvedParameter(
       (pi, ctx) => pi.ParameterType == typeof(ISender), 
       (pi, ctx) => ctx.ResolveKeyed<ISender>("notification"))); 

विकल्प 4: मेटाडाटा

builder.RegisterType<PostalServiceSender>() 
      .As<ISender>() 
      .WithMetadata("SendAllowed", "order"); 
    builder.RegisterType<EmailNotifier>() 
      .As<ISender>() 
      .WithMetadata("SendAllowed", "notification"); 

builder.RegisterType<ShippingProcessor>() 
      .WithParameter(
      new ResolvedParameter(
       (pi, ctx) => pi.ParameterType == typeof(ISender), 
       (pi, ctx) => ctx.Resolve<IEnumerable<Meta<ISender>>>() 
           .First(a => a.Metadata["SendAllowed"].Equals("order")))); 
    builder.RegisterType<CustomerNotifier>(); 
      .WithParameter(
      new ResolvedParameter(
       (pi, ctx) => pi.ParameterType == typeof(ISender), 
       (pi, ctx) => ctx.Resolve<IEnumerable<Meta<ISender>>>() 
           .First(a => a.Metadata["SendAllowed"].Equals("notification"))));