AddTransient, AddScoped और AddSingleton: C# सेवा जीवनचक्र में कैसे भ्रमित न हों
\n\nक्या आपने कभी सोचा है: "मेरी सेवा अनुरोधों के बीच डेटा क्यों सहेज रही है, जबकि मैंने ऐसा नहीं कहा?" या इसके विपरीत — "हर बार एक नई वस्तु क्यों बनती है, और मैं स्थिति खो रहा हूँ?"
\n\nASP.NET Core में निर्भरता इंजेक्शन (Dependency Injection, DI) की दुनिया में आपका स्वागत है! यह शुरुआती लोगों के लिए सबसे शक्तिशाली और साथ ही भ्रमित करने वाले विषयों में से एक है। आज हम उन तीन स्तंभों पर चर्चा करेंगे जिन पर C# में वस्तु प्रबंधन टिका है: AddTransient, AddScoped और AddSingleton।
इस लेख के अंत तक, आप न केवल अंतर समझेंगे, बल्कि साक्षात्कार में इस प्रश्न का आत्मविश्वास से उत्तर भी दे पाएंगे (हाँ, यह पूछा जाना पसंद है!)। चलिए शुरू करते हैं!
\n\nसेवा जीवनचक्र क्या है और इसकी आवश्यकता क्यों है?
\n\nकल्पना करें कि आपका एप्लिकेशन एक रेस्तरां है। सेवाएँ रसोइए, वेटर और बर्तन हैं। जीवनचक्र यह निर्धारित करता है कि वे कितने समय तक "जीवित" रहते हैं:
\n\n- \n
- Transient (क्षणिक) — एक बार उपयोग होने वाला कर्मचारी। आया, सूप की एक प्लेट बनाई और चला गया। नया ऑर्डर — नया कर्मचारी। \n
- Scoped (दायरे में) — एक शिफ्ट का कर्मचारी। जब तक रेस्तरां खुला है (जब तक HTTP अनुरोध चलता है) सभी ग्राहकों की सेवा करता है। \n
- Singleton (एकल) — शेफ जो रेस्तरां के पूरे जीवनकाल काम करता है। पूरे एप्लिकेशन के लिए एक। \n
C# में, यह तर्क अंतर्निहित DI कंटेनर के माध्यम से कार्यान्वित किया जाता है। आइए कोड देखें।
\n\n1. AddTransient — हर बार नया उदाहरण
\n\nकब उपयोग करें: बिना स्थिति वाली (stateless) हल्की सेवाएँ जो कॉल के बीच डेटा संग्रहीत नहीं करती हैं। रिपॉजिटरी, हेल्पर, उपयोगिताओं के लिए आदर्श।
\n\nयह कैसे काम करता है: हर बार जब आप सेवा का अनुरोध करते हैं (कंस्ट्रक्टर के माध्यम से या सीधे कंटेनर से), एक नई वस्तु बनाई जाती है।
\n\n// Program.cs में पंजीकरण\nbuilder.Services.AddTransient<IMyService, MyService>();\n\n// सेवा का उदाहरण\npublic interface IMyService\n{\n Guid GetInstanceId();\n}\n\npublic class MyService : IMyService\n{\n private readonly Guid _id = Guid.NewGuid();\n public Guid GetInstanceId() => _id;\n}\n\n// कंट्रोलर जो सेवा का उपयोग करता है\npublic class HomeController : Controller\n{\n private readonly IMyService _service1;\n private readonly IMyService _service2;\n\n public HomeController(IMyService service1, IMyService service2)\n {\n _service1 = service1;\n _service2 = service2;\n }\n\n public IActionResult Index()\n {\n ViewBag.Id1 = _service1.GetInstanceId();\n ViewBag.Id2 = _service2.GetInstanceId();\n // Id1 और Id2 — अलग-अलग GUID हैं!\n return View();\n }\n}\n\n\nमहत्वपूर्ण: एक ही HTTP अनुरोध के भीतर भी, यदि आप IMyService को दो अलग-अलग स्थानों पर इंजेक्ट करते हैं, तो आपको दो अलग-अलग वस्तुएँ मिलेंगी। मेमोरी खर्च होती है, लेकिन डेटा "दूषित" होने का कोई जोखिम नहीं है।
2. AddScoped — प्रति अनुरोध एक उदाहरण
\n\nकब उपयोग करें: ऐसी सेवाएँ जो एक HTTP अनुरोध के दायरे में सुसंगत होनी चाहिए। उदाहरण के लिए, Entity Framework Core में DbContext, शॉपिंग कार्ट सेवाएँ, अनुरोध लॉगर।
यह कैसे काम करता है: एक HTTP अनुरोध (या scope) के भीतर, एक एक उदाहरण बनाया जाता है। यदि आप इसे कई बार अनुरोध करते हैं — तो आपको वही वस्तु मिलती है। लेकिन किसी अन्य उपयोगकर्ता का प्रत्येक नया अनुरोध अपना उदाहरण प्राप्त करेगा।
\n\n// पंजीकरण\nbuilder.Services.AddScoped<IScopedService, ScopedService>();\n\npublic interface IScopedService\n{\n Guid GetInstanceId();\n}\n\npublic class ScopedService : IScopedService\n{\n private readonly Guid _id = Guid.NewGuid();\n public Guid GetInstanceId() => _id;\n}\n\n// उसी कंट्रोलर में\npublic