खोज…


परिचय

Aspnet Core अपनी प्रमुख कोर अवधारणाओं में से एक के रूप में निर्भरता इंजेक्शन के साथ बनाया गया है। यह एक अनुरूप कंटेनर अमूर्तता का परिचय देता है ताकि आप अपनी पसंद के तीसरे पक्ष के कंटेनर के साथ बिलिन को बदल सकें।

वाक्य - विन्यास

  • IServiceCollection.Add(ServiceDescriptor item);
  • IServiceCollection.AddScoped(Type serviceType);
  • IServiceCollection.AddScoped(Type serviceType, Type implementationType);
  • IServiceCollection.AddScoped(Type serviceType, Func<IServiceProvider, object> implementationFactory);
  • IServiceCollection.AddScoped<TService>()
  • IServiceCollection.AddScoped<TService>(Func<IServiceProvider, TService> implementationFactory)
  • IServiceCollection.AddScoped<TService, TImplementation>()
  • IServiceCollection.AddScoped<TService, TImplementation>(Func<IServiceProvider, TImplementation> implementationFactory)
  • IServiceCollection.AddSingleton(Type serviceType);
  • IServiceCollection.AddSingleton(Type serviceType, Func<IServiceProvider, object> implementationFactory);
  • IServiceCollection.AddSingleton(Type serviceType, Type implementationType);
  • IServiceCollection.AddSingleton(Type serviceType, object implementationInstance);
  • IServiceCollection.AddSingleton<TService>()
  • IServiceCollection.AddSingleton<TService>(Func<IServiceProvider, TService> implementationFactory)
  • IServiceCollection.AddSingleton<TService>(TService implementationInstance)
  • IServiceCollection.AddSingleton<TService, TImplementation>()
  • IServiceCollection.AddSingleton<TService, TImplementation>(Func<IServiceProvider, TImplementation> implementationFactory)
  • IServiceCollection.AddTransient(Type serviceType);
  • IServiceCollection.AddTransient(Type serviceType, Func<IServiceProvider, object> implementationFactory);
  • IServiceCollection.AddTransient(Type serviceType, Type implementationType);
  • IServiceCollection.AddTransient<TService>()
  • IServiceCollection.AddTransient<TService>(Func<IServiceProvider, TService> implementationFactory)
  • IServiceCollection.AddTransient<TService, TImplementation>()
  • IServiceCollection.AddTransient<TService, TImplementation>(Func<IServiceProvider, TImplementation> implementationFactory)
  • IServiceProvider.GetService(Type serviceType)
  • IServiceProvider.GetService<T>()
  • IServiceProvider.GetServices(Type serviceType)
  • IServiceProvider.GetServices<T>()

टिप्पणियों

IServiceProvider विधियों के सामान्य वेरिएंट का उपयोग करने के लिए आपको निम्नलिखित नामस्थान शामिल करने होंगे:

using Microsoft.Extensions.DependencyInjection;

रजिस्टर और मैन्युअल हल

निर्भरता का वर्णन करने का पसंदीदा तरीका कंस्ट्रक्टर इंजेक्शन का उपयोग करके है जो स्पष्ट निर्भरता सिद्धांत का अनुसरण करता है:

ITestService.cs

public interface ITestService
{
    int GenerateRandom();
}

TestService.cs

public class TestService : ITestService
{
    public int GenerateRandom()
    {
        return 4;
    }
}

Startup.cs (कॉन्फ़िगर सेवाएँ)

public void ConfigureServices(IServiceCollection services)
{
    // ...

    services.AddTransient<ITestService, TestService>();
}

HomeController.cs

using Microsoft.Extensions.DependencyInjection;

namespace Core.Controllers
{
    public class HomeController : Controller
    {
        public HomeController(ITestService service)
        {
            int rnd = service.GenerateRandom();
        }
    }
}

निर्भरता दर्ज करें

बिल्टिन कंटेनर निर्मित सुविधाओं के एक सेट के साथ आता है:

आजीवन नियंत्रण

public void ConfigureServices(IServiceCollection services)
    {
        // ...
    
        services.AddTransient<ITestService, TestService>();
        // or
        services.AddScoped<ITestService, TestService>();
        // or
        services.AddSingleton<ITestService, TestService>();
        // or
        services.AddSingleton<ITestService>(new TestService());
    }
  • AddTransient : हर बार इसे हल किया गया है
  • AddScoped : अनुरोध के अनुसार एक बार बनाया गया
  • AddSingleton : लेज़ीली प्रति एप्लिकेशन एक बार बनाया गया
  • AddSingleton (उदाहरण) : प्रति एप्लिकेशन पहले बनाया गया उदाहरण प्रदान करता है

असंख्य निर्भरताएँ

यह भी निर्भरता रजिस्टर करने के लिए संभव है:

 services.TryAddEnumerable(ServiceDescriptor.Transient<ITestService, TestServiceImpl1>());
 services.TryAddEnumerable(ServiceDescriptor.Transient<ITestService, TestServiceImpl2>());

आप फिर उन्हें निम्न प्रकार से उपभोग कर सकते हैं:

public class HomeController : Controller
{
    public HomeController(IEnumerable<ITestService> services)
    {
        // do something with services.
    }
}

सामान्य निर्भरता

आप सामान्य निर्भरता भी दर्ज कर सकते हैं:

services.Add(ServiceDescriptor.Singleton(typeof(IKeyValueStore<>), typeof(KeyValueStore<>)));

और फिर इसका सेवन इस प्रकार करें:

public class HomeController : Controller
{
    public HomeController(IKeyValueStore<UserSettings> userSettings)
    {
        // do something with services.
    }
}

एक नियंत्रक पर निर्भरता प्राप्त करें

एक बार पंजीकृत होने के बाद कंट्रोलर कंस्ट्रक्टर पर पैरामीटर जोड़कर एक निर्भरता प्राप्त की जा सकती है।

// ...
using System;
using Microsoft.Extensions.DependencyInjection;

namespace Core.Controllers
{
    public class HomeController : Controller
    {
        public HomeController(ITestService service)
        {
            int rnd = service.GenerateRandom();
        }
    }
}

एक नियंत्रक कार्रवाई में एक निर्भरता इंजेक्शन

एक कम ज्ञात अंतर्निहित सुविधा FromServicesAttribute का उपयोग करके कंट्रोलर एक्शन इंजेक्शन है।

[HttpGet]
public async Task<IActionResult> GetAllAsync([FromServices]IProductService products)
{
     return Ok(await products.GetAllAsync());
}

एक महत्वपूर्ण नोट यह है कि [FromServices] को सामान्य "संपत्ति इंजेक्शन" या "विधि इंजेक्शन" तंत्र के रूप में उपयोग नहीं किया जा सकता है! यह केवल एक नियंत्रक क्रिया या नियंत्रक निर्माण के विधि मापदंडों पर इस्तेमाल किया जा सकता है (हालांकि यह ASP में पुराना है, क्योंकि ASP.NET Core DI सिस्टम पहले से ही कंस्ट्रक्टर इंजेक्शन का उपयोग करता है और इसके लिए अतिरिक्त मार्करों की आवश्यकता नहीं है)।

यह एक नियंत्रकों, नियंत्रक कार्रवाई के बाहर कहीं भी इस्तेमाल नहीं किया जा सकता है । इसके अलावा यह ASP.NET Core MVC के लिए बहुत विशिष्ट है और Microsoft.AspNetCore.Mvc.Core विधानसभा में रहता है।

इस विशेषता के बारे में ASP.NET कोर MVC GitHub मुद्दे ( सीमा [केवल सेवाओं के लिए लागू करने के लिए ) से मूल उद्धरण):

@rynowak:

@Eilon:

गुणों के साथ समस्या यह है कि यह कई लोगों को प्रतीत होता है कि इसे किसी भी वस्तु की किसी भी संपत्ति पर लागू किया जा सकता है।

सहमत थे, हमारे पास उपयोगकर्ताओं द्वारा कई मुद्दों को भ्रम के साथ पोस्ट किया गया था कि इस सुविधा का उपयोग कैसे किया जाना चाहिए। वास्तव में दोनों प्रकार की प्रतिक्रिया की एक बड़ी मात्रा है "[FromServices] अजीब है और मुझे यह पसंद नहीं है" और "[FromServices] ने मुझे भ्रमित किया है"। यह एक जाल की तरह लगता है, और ऐसा कुछ जो टीम अभी भी वर्षों के सवालों के जवाब दे रही होगी।

हम [FromServices] के लिए सबसे मूल्यवान परिदृश्य की तरह महसूस करते हैं एक सेवा के लिए एक कार्यविधि के लिए विधि पैरामीटर पर है जो आपको केवल उस एक स्थान पर चाहिए।

/ cc @ danroth27 - डॉक्स बदलता है

वर्तमान [FromServices] के प्यार में किसी के लिए, मैं दृढ़ता से एक DI प्रणाली की तलाश करने की सलाह दूंगा जो संपत्ति इंजेक्शन (उदाहरण के लिए ऑटोफाक) कर सकता है।

टिप्पणियाँ:

  • .NET कोर डिपेंडेंसी इंजेक्शन प्रणाली के साथ पंजीकृत कोई भी सेवाएं [FromServices] विशेषता का उपयोग करके एक नियंत्रक की कार्रवाई के अंदर इंजेक्ट की जा सकती है।

  • सबसे अधिक प्रासंगिक मामला तब है जब आपको केवल एक एक्शन विधि में एक सेवा की आवश्यकता होती है और अपने नियंत्रक के निर्माता को किसी अन्य निर्भरता के साथ अव्यवस्थित नहीं करना चाहते हैं, जिसका उपयोग केवल एक बार किया जाएगा।

  • ASP.NET Core MVC (अर्थात शुद्ध .NET फ्रेमवर्क या .NET कोर कंसोल एप्लिकेशन) के बाहर उपयोग नहीं किया जा सकता है, क्योंकि यह Microsoft.AspNetCore.Mvc.Core असेंबली में रहता है।

  • संपत्ति या विधि इंजेक्शन के लिए आपको उपलब्ध थर्ड पार्टी IoC कंटेनरों में से एक (ऑटोफैक, यूनिटी आदि) का उपयोग करना चाहिए।

विकल्प पैटर्न / सेवाओं में इंजेक्शन विकल्प

ASP.NET Core के साथ Microsoft टीम ने विकल्प पैटर्न भी पेश किया है, जो मजबूत टाइप किए गए विकल्प और एक बार आपकी सेवाओं में विकल्पों को इंजेक्ट करने की क्षमता को कॉन्फ़िगर करने की अनुमति देता है।

पहले हम एक मजबूत टाइप क्लास के साथ शुरुआत करते हैं, जो हमारे कॉन्फ़िगरेशन को होल्ड करेगा।

public class MySettings 
{
    public string Value1 { get; set; }
    public string Value2 { get; set; }
}

और appsettings.json में एक प्रविष्टि।

{
  "mysettings" : {
    "value1": "Hello",
    "value2": "World"
  }
}

इसके बाद हम इसे स्टार्टअप क्लास में इनिशियलाइज़ करते हैं। इसे करने के दो तरीके हैं

  1. इसे सीधे appsettings.json "mysettings" अनुभाग से लोड करें

    services.Configure<MySettings>(Configuration.GetSection("mysettings"));
    
  2. इसे मैन्युअल रूप से करें

    services.Configure<MySettings>(new MySettings 
    {
        Value1 = "Hello",
        Value2 = Configuration["mysettings:value2"]
    });
    

    appsettings.json प्रत्येक पदानुक्रम स्तर को a : द्वारा अलग किया जाता है। चूंकि value2 mysettings ऑब्जेक्ट की एक संपत्ति है, हम इसे mysettings:value2 माध्यम से एक्सेस करते हैं।

अंत में हम IOptions<T> इंटरफ़ेस का उपयोग करके विकल्पों को अपनी सेवाओं में इंजेक्ट कर सकते हैं

public class MyService : IMyService
{
    private readonly MySettings settings;

    public MyService(IOptions<MySettings> mysettings) 
    {
        this.settings = mySettings.Value;
    }
}

टिप्पणियों

यदि स्टार्टअप के दौरान IOptions<T> कॉन्फ़िगर नहीं किया गया है, तो IOptions<T> को इंजेक्ट करने से T वर्ग का डिफ़ॉल्ट उदाहरण इंजेक्ट होगा।

एप्लिकेशन स्टार्टअप / डेटाबेस सीडिंग के दौरान स्कोप की गई सेवाओं का उपयोग करना

एप्लिकेशन स्टार्टअप के दौरान scoped सेवाओं को हल करना मुश्किल हो सकता है, क्योंकि कोई अनुरोध नहीं है और इसलिए कोई scoped सेवा नहीं है।

एप्लिकेशन स्टार्टअप के माध्यम से app.ApplicationServices.GetService<AppDbContext>() स्टार्टअप के माध्यम से एक app.ApplicationServices.GetService<AppDbContext>() सेवा को हल करना। ऐप्लिकेशंस app.ApplicationServices.GetService<AppDbContext>() कारण समस्याएँ पैदा हो सकती हैं, क्योंकि यह वैश्विक कंटेनर के दायरे में बनाई जाएगी, प्रभावी रूप से इसे एप्लिकेशन के जीवनकाल के साथ एक एकल बना देगा, जिससे नेतृत्व हो सकता है। Cannot access a disposed object in ASP.NET Core when injecting DbContext

निम्नलिखित पैटर्न पहले एक नया स्कोप बनाकर समस्या को हल करता है और फिर उसमें से स्कोप की गई सेवाओं को हल करता है, फिर एक बार काम पूरा हो जाने के बाद, स्कोप्ड कंटेनर को डिस्पोज़ कर देता है।

public Configure(IApplicationBuilder app)
{
    // serviceProvider is app.ApplicationServices from Configure(IApplicationBuilder app) method
    using (var serviceScope = app.ApplicationServices.GetRequiredService<IServiceScopeFactory>().CreateScope())
    {
        var db = serviceScope.ServiceProvider.GetService<AppDbContext>();

        if (await db.Database.EnsureCreatedAsync())
        {
            await SeedDatabase(db);
        }
    }
}

यह एप्लिकेशन स्टार्टअप के दौरान डेटा को सीड करने के लिए एंटिटी फ्रेमवर्क कोर टीम का एक अर्ध-आधिकारिक तरीका है और संगीतस्टोर नमूना आवेदन में परिलक्षित होता है।

डिपेंडेंसी इंजेक्शन के माध्यम से कंट्रोलर्स, व्यूकॉमर्स और टैग हेल्पर्स को हल करें

डिफ़ॉल्ट नियंत्रकों द्वारा, ViewCompords और TagHelpers निर्भरता इंजेक्शन कंटेनर के माध्यम से पंजीकृत और हल नहीं किए जाते हैं। ऐसा करने में असमर्थता का परिणाम है, जब ऑटोफेक जैसे नियंत्रण (IoC) कंटेनर के तीसरे पक्ष के व्युत्क्रम का उपयोग करते हुए संपत्ति इंजेक्शन।

ASP.NET Core MVC को आईओसी के माध्यम से इन प्रकारों को भी हल करने के लिए, एक को Startup.cs में निम्नलिखित पंजीकरणों को जोड़ने की जरूरत है (GitHub पर आधिकारिक नियंत्रण-नियंत्रक नमूना से लिया गया)

public void ConfigureServices(IServiceCollection services)
{
    var builder = services
        .AddMvc()
        .ConfigureApplicationPartManager(manager => manager.ApplicationParts.Clear())
        .AddApplicationPart(typeof(TimeScheduleController).GetTypeInfo().Assembly)
        .ConfigureApplicationPartManager(manager =>
        {
            manager.ApplicationParts.Add(new TypesPart(
              typeof(AnotherController),
              typeof(ComponentFromServicesViewComponent),
              typeof(InServicesTagHelper)));

            manager.FeatureProviders.Add(new AssemblyMetadataReferenceFeatureProvider());
        })
        .AddControllersAsServices()
        .AddViewComponentsAsServices()
        .AddTagHelpersAsServices();

    services.AddTransient<QueryValueService>();
    services.AddTransient<ValueService>();
    services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
}

सादा निर्भरता इंजेक्शन उदाहरण (बिना स्टार्टअप के)

इससे आपको पता चलता है कि Microsoft का उपयोग कैसे किया जाता है। एक्सटेंसन डी डिपेंडेंसीइन्जेक्शन नगेट पैकेज का उपयोग बिना WebHostBuilder से केस्टेल से किया जाता है (जैसे जब आप कुछ और बनाना चाहते हैं तो वेबएप):

internal class Program
{
    public static void Main(string[] args)
    {
        var services = new ServiceCollection(); //Creates the service registry
        services.AddTransient<IMyInterface, MyClass>(); //Add registration of IMyInterface (should create an new instance of MyClass every time)
        var serviceProvider = services.BuildServiceProvider(); //Build dependencies into an IOC container
        var implementation = serviceProvider.GetService<IMyInterface>(); //Gets a dependency

        //serviceProvider.GetService<ServiceDependingOnIMyInterface>(); //Would throw an error since ServiceDependingOnIMyInterface is not registered
        var manualyInstaniate = new ServiceDependingOnIMyInterface(implementation); 

        services.AddTransient<ServiceDependingOnIMyInterface>();
        var spWithService = services.BuildServiceProvider(); //Generaly its bad practise to rebuild the container because its heavey and promotes use of anti-pattern.
        spWithService.GetService<ServiceDependingOnIMyInterface>(); //only now i can resolve
    }
}

interface IMyInterface
{
}

class MyClass : IMyInterface
{
}

class ServiceDependingOnIMyInterface
{
    private readonly IMyInterface _dependency;

    public ServiceDependingOnIMyInterface(IMyInterface dependency)
    {
        _dependency = dependency;
    }
}

Microsoft की आंतरिक कार्यप्रणाली

IServiceCollection

Microsoft के DI nuget पैकेज के साथ IOC कंटेनर का निर्माण शुरू करने के लिए आप IServiceCollection बनाना शुरू करते हैं। आप पहले से ही प्रदान किए गए संग्रह का उपयोग कर सकते हैं: ServiceCollection :

var services = new ServiceCollection();

यह IServiceCollection कार्यान्वयन के अलावा और कुछ नहीं है: IList<ServiceDescriptor>, ICollection<ServiceDescriptor>, IEnumerable<ServiceDescriptor>, IEnumerable

सूची में ServiceDescriptor उदाहरण जोड़ने के लिए सभी निम्नलिखित विधियाँ केवल विस्तार विधियाँ हैं:

services.AddTransient<Class>(); //add registration that is always recreated
services.AddSingleton<Class>(); // add registration that is only created once and then re-used
services.AddTransient<Abstract, Implementation>(); //specify implementation for interface
services.AddTransient<Interface>(serviceProvider=> new Class(serviceProvider.GetService<IDependency>())); //specify your own resolve function/ factory method.
services.AddMvc(); //extension method by the MVC nuget package, to add a whole bunch of registrations.
// etc..

//when not using an extension method:
services.Add(new ServiceDescriptor(typeof(Interface), typeof(Class)));

IServiceProvider

सर्विसप्रोवाइडर सभी पंजीकरणों में से एक 'संकलन' है, ताकि उनका उपयोग जल्दी से किया जा सके, यह services.BuildServiceProvider() साथ किया जा सकता है। BuildServiceProvider services.BuildServiceProvider() जो मूल रूप से इसके लिए एक एक्सटेंशन mehtod है:

var provider = new ServiceProvider( services, false); //false is if it should validate scopes

IServiceCollection में प्रत्येक ServiceDescriptor के दृश्यों के पीछे एक फैक्ट्री विधि Func<ServiceProvider, object> जहाँ ऑब्जेक्ट रिटर्न प्रकार है और संकलित किया जाता है: इंप्लीमेंटेशन टाइप, सिंगर या आपकी स्वयं की फैक्ट्री विधि का बनाया गया उदाहरण।

ये पंजीकरण ServiceTable जोड़े जाते हैं जो मूल रूप से एक ConcurrentDictionary जिसमें कुंजी ServiceType और ऊपर बताई गई फैक्टरी विधि के मान के साथ है।

परिणाम

अब हमारे पास एक ConcurrentDictionary<Type, Func<ServiceProvider, object>> जो हम समवर्ती का उपयोग करके हमारे लिए सेवाएं बनाने के लिए कह सकते हैं। यह कैसे दिख सकता है इसका एक मूल उदाहरण दिखाने के लिए।

  var serviceProvider = new ConcurrentDictionary<Type, Func<ServiceProvider, object>>();
  var factoryMethod = serviceProvider[typeof(MyService)];
  var myServiceInstance = factoryMethod(serviceProvider)

यह कैसे काम करता है यह नहीं है!

यह ConcurrentDictionary ServiceTable का एक गुण है जो ServiceProvider की संपत्ति है



Modified text is an extract of the original Stack Overflow Documentation
के तहत लाइसेंस प्राप्त है CC BY-SA 3.0
से संबद्ध नहीं है Stack Overflow