14

के साथ प्रति थ्रेड और प्रति वेब अनुरोध के लिए मिश्रित जीवनशैली मैं अपनी आईओसी लाइब्रेरी के रूप में SimpleInjector का उपयोग कर रहा हूं। मैं वेब अनुरोध के अनुसार DbContext पंजीकृत करता हूं और यह ठीक काम करता है। लेकिन एक कार्य है जिसे मैं इसे पृष्ठभूमि धागे में चलाता हूं। इसलिए, मुझे DbContext उदाहरण बनाने में कोई समस्या है। जैसेसरल इंजेक्टर

  1. Service1DbContext
  2. Service2 का एक उदाहरण है पृष्ठभूमि धागे से DbContext
  3. Service1 और Service2 रन का एक उदाहरण है।
  4. Service1 एक इकाई को हासिल करेगा और यह Service2
  5. Service2 को पारित उस संस्था का उपयोग करता है, लेकिन इकाई DbContext

से अलग है वास्तव में समस्या यहाँ है: Service1.DbContextService2.DbContext से अंतर है।

ऐसा लगता है जब मैं एएसपी.नेट एमवीसी, SimpleInjector में एक अलग थ्रेड में कोई कार्य चलाता हूं, प्रत्येक कॉल के लिए DbContext का एक नया उदाहरण बनाता है। जबकि कुछ आईओसी पुस्तकालय (उदाहरण के लिए StructureMap) प्रति-थ्रेड-प्रति-वेबरेक्वेस्ट के लिए मिश्रित जीवनशैली है, ऐसा लगता है कि SimpleInjector में कोई नहीं है। क्या मैं सही हू?

क्या आपको SimpleInjector में इस समस्या को हल करने का कोई विचार है? अग्रिम धन्यवाद।

संपादित करें:

मेरे सेवाओं यहां हैं:

class Service1 : IService1 { 
    public Service1(MyDbContext context) { } 
} 

class Service2 : IService2 { 
    public Service2(MyDbContext context, IService1 service1) { } 
} 

class SyncServiceUsage { 
    public SyncServiceUsage(Service2 service2) { 
     // use Service2 (and Service1 and DbContext) from HttpContext.Current 
    } 
} 

class AsyncServiceUsage { 
    public AsyncServiceUsage(Service2 service2) { 
     // use Service2 (and Service1 and DbContext) from background thread 
    } 
} 

public class AsyncCommandHandlerDecorator<TCommand> 
    : ICommandHandler<TCommand> where TCommand : ICommand { 

    private readonly Func<ICommandHandler<TCommand>> _factory; 

    public AsyncCommandHandlerDecorator(Func<ICommandHandler<TCommand>> factory) { 
     _factory = factory; 
    } 

    public void Handle(TCommand command) { 
     ThreadPool.QueueUserWorkItem(_ => { 
      // Create new handler in this thread. 
      var handler = _factory(); 
      handler.Handle(command); 
     }); 
    } 
} 

void InitializeSimpleInjector() { 
    register AsyncCommandHandlerDecorator for services (commands actually) that starts with "Async" 
} 

मैं उपयोगकर्ता Service2 कभी कभी और AsyncService2 दूसरी बार।

+0

संबंधित: http://stackoverflow.com/questions/11041601/simple-injector-multi-threading-in-mvc3-asp-net – Steven

+0

संबंधित: http://stackoverflow.com/questions/10304023/simpleinjector-is -इस-द-राइट-वे-टू-रजिस्टरमैन्योरोपेंजेनेरिक-कब-मेरे पास – Steven

उत्तर

17

ऐसा लगता है जब मैं ASP.NET MVC में एक अलग थ्रेड में एक कार्य चलाने के लिए, SimpleInjector प्रत्येक कॉल के लिए DbContext का एक नया उदाहरण बनाता है।

सरल इंजेक्टर v1.5 की RegisterPerWebRequest जीवन शैली के व्यवहार और नीचे एक क्षणिक उदाहरण वापस जाने के लिए जब उदाहरणों एक वेब अनुरोध के संदर्भ (जहां HttpContext.Current रिक्त है) के बाहर अनुरोध कर रहे हैं है। एक क्षणिक उदाहरण लौटाना सरल इंजेक्टर में एक डिज़ाइन दोष था, क्योंकि इससे अनुचित उपयोग को छिपाना आसान हो जाता है। Version 1.6 of the Simple Injector गलत तरीके से एक क्षणिक उदाहरण लौटने के बजाय अपवाद फेंक देगा, स्पष्ट रूप से संवाद करने के लिए कि आपने कंटेनर को गलत तरीके से कॉन्फ़िगर किया है।

जबकि (उदाहरण के StructureMap के लिए) कुछ आईओसी पुस्तकालयों प्रति-धागा-प्रति-webrequest के लिए एक मिश्रित जीवन शैली है, ऐसा लगता है सरल इंजेक्टर है नहीं एक

यह सही है कि सरल इंजेक्टर कुछ कारणों से मिश्रित जीवन शैली के लिए कोई अंतर्निहित समर्थन नहीं है। सबसे पहले यह एक विदेशी विशेषता है कि बहुत से लोगों को जरूरत नहीं है। दूसरा, आप किसी भी दो या तीन जीवन शैली को एक साथ मिश्रित कर सकते हैं, ताकि यह संकर का लगभग अंतहीन संयोजन होगा।और आखिरकार, यह (सुंदर) आसान है इसे स्वयं पंजीकृत करें।

यद्यपि आप Per Thread जीवन शैली के साथ Per Web Request मिश्रण कर सकते हैं, यह शायद बेहतर हो जब तुम Per Lifetime Scope साथ प्रति वेब अनुरोध मिश्रण, लाइफटाइम स्कोप के साथ के बाद से आप स्पष्ट रूप से शुरू करने और गुंजाइश खत्म (और जब गुंजाइश समाप्त हो जाती है DbContext निपटान कर सकते हैं) होगा ।

Simple Injector 2 से और, आप Lifestyle.CreateHybrid विधि का उपयोग करके आसानी से किसी भी जीवन शैली को मिश्रित कर सकते हैं। Simple Injector: multi-threading in MVC3 ASP.NET

अद्यतन

अपने अद्यतन के बारे में:

var hybridLifestyle = Lifestyle.CreateHybrid(
    () => HttpContext.Current != null, 
    new WebRequestLifestyle(), 
    new LifetimeScopeLifestyle()); 

// Register as hybrid PerWebRequest/PerLifetimeScope. 
container.Register<DbContext, MyDbContext>(hybridLifestyle); 

एक और Stackoverflow सवाल है कि इस विषय पर एक सा गहरी, आप एक बार देख लेने के लिए चाहते हो सकता है में चला जाता है नहीं है: यहाँ एक उदाहरण है। आप लगभग वहाँ हैं। पृष्ठभूमि थ्रेड पर चलने वाले आदेशों को लाइफटाइम स्कोप के भीतर चलाने की आवश्यकता है, इसलिए आपको इसे स्पष्ट रूप से प्रारंभ करना होगा। यहां नई चाल पर BeginLifetimeScope पर कॉल करना है, लेकिन वास्तविक कमांड हैंडलर (और इसकी निर्भरता) बनने से पहले। दूसरे शब्दों में, ऐसा करने का सबसे अच्छा तरीका सजावट के अंदर है। के बाद से इस डेकोरेटर दोनों एक नया धागा पर आदेशों चलाता है,

public class AsyncCommandHandlerDecorator<TCommand> 
    : ICommandHandler<TCommand> where TCommand : ICommand 
{ 
    private readonly Container _container; 
    private readonly Func<ICommandHandler<TCommand>> _factory; 

    public AsyncCommandHandlerDecorator(Container container, 
     Func<ICommandHandler<TCommand>> factory) 
    { 
     _container = container; 
     _factory = factory; 
    } 

    public void Handle(TCommand command) 
    { 
     ThreadPool.QueueUserWorkItem(_ => 
     { 
      using (_container.BeginLifetimeScope()) 
      { 
       // Create new handler in this thread 
       // and inside the lifetime scope. 
       var handler = _factory(); 
       handler.Handle(command); 
      } 
     }); 
    } 
} 

जहां शुद्धतावादियों की वकालत कि SOLID सिद्धांतों चिल्लाना होगा कि इस वर्ग के Single Responsibility Principle उल्लंघन कर रहा है:

सबसे आसान समाधान अपने AsyncCommandHandlerDecorator अद्यतन करने के लिए गुंजाइश को जोड़ने के लिए है और एक नया जीवनकाल गुंजाइश शुरू करता है। मैं इसके बारे में ज्यादा चिंता नहीं करता, क्योंकि मुझे लगता है कि बैकग्राउंड थ्रेड शुरू करने और जीवन भर के दायरे को शुरू करने के बीच घनिष्ठ संबंध है (आप वैसे भी किसी के बिना किसी का उपयोग नहीं करेंगे)। लेकिन फिर भी, आप आसानी से AsyncCommandHandlerDecorator अछूता छोड़ दें और इस प्रकार एक नया LifetimeScopedCommandHandlerDecorator बना सकते हैं:

public class LifetimeScopedCommandHandlerDecorator<TCommand> 
    : ICommandHandler<TCommand> where TCommand : ICommand 
{ 
    private readonly Container _container; 
    private readonly Func<ICommandHandler<TCommand>> _factory; 

    public LifetimeScopedCommandHandlerDecorator(Container container, 
     Func<ICommandHandler<TCommand>> factory) 
    { 
     _container = container; 
     _factory = factory; 
    } 

    public void Handle(TCommand command) 
    { 
     using (_container.BeginLifetimeScope()) 
     { 
      // The handler must be created inside the lifetime scope. 
      var handler = _factory(); 
      handler.Handle(command); 
     } 
    } 
} 

जिस क्रम में इन सज्जाकार पाठ्यक्रम आवश्यक की है पंजीकृत हैं, के बाद से AsyncCommandHandlerDecoratorLifetimeScopedCommandHandlerDecorator लपेट चाहिए। इसका मतलब है कि LifetimeScopedCommandHandlerDecorator पंजीकरण पहले आना चाहिए: और अधिक विस्तार से इस बारे में

container.RegisterDecorator(typeof(ICommandHandler<>), 
    typeof(LifetimeScopedCommandHandlerDecorator<>), 
    backgroundCommandCondition); 

container.RegisterDecorator(typeof(ICommandHandler<>), 
    typeof(AsyncCommandHandlerDecorator<>), 
    backgroundCommandCondition); 

This old Stackoverflow question बात करती है। आपको निश्चित रूप से एक नज़र रखना चाहिए।

+1

धन्यवाद + स्टीवन मैंने अन्य लिंक और इसके उपयोगी और सहायक को पढ़ा। साथ ही, मैंने 'सरल इंजेक्टर' प्रतिष्ठा को बेहतर बनाने के लिए उत्तर और प्रश्न सभी को वोट दिया। शुभकामनाएं –

+0

डब्ल्यूटीएफ मैं उलझन में हूँ! मैं अपना प्रश्न संपादित करता हूं। क्या आप मुझे उपयोग के बारे में बता सकते हैं? 'सेवा 1' और' सेवा 2 'ऑब्जेक्ट्स का उपयोग मुख्य थ्रेड (वेब ​​अनुरोध) और पृष्ठभूमि धागे दोनों में किया जाता है। मैं ऐसा करने में सक्षम होना चाहता हूँ। और मैं ctor इंजेक्शन द्वारा उन्हें 'डीबीकॉन्टेक्स्ट' इंजेक्ट करता हूं। क्या मुझे अपना कार्यान्वयन बदलना चाहिए? –

+1

@Javad_Amiry: मुझे अपने देर के उत्तर के लिए खेद है, लेकिन डेवलपर्स को कभी-कभी कुछ आराम की ज़रूरत होती है ;-)। मैंने अपना जवाब अपडेट किया। आशा है कि ये आपकी मदद करेगा। – Steven

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