c# - حل المثيلات باستخدام ASP.NET Core DI




dependency-injection asp.net-core (4)

إذا قمت بإنشاء تطبيق باستخدام قالب ، فستحصل على شيء مثل هذا في فئة Startup :

public void ConfigureServices(IServiceCollection services)
{
    // Add framework services.
    services.AddApplicationInsightsTelemetry(Configuration);

    services.AddMvc();
}

يمكنك بعد ذلك إضافة تبعيات هناك ، على سبيل المثال:

services.AddTransient<ITestService, TestService>();

إذا كنت ترغب في الوصول إلى ITestService على وحدة التحكم الخاصة بك ، يمكنك إضافة IServiceProvider على المُنشئ وسيتم حقنه:

public HomeController(IServiceProvider serviceProvider)

ثم يمكنك حل الخدمة التي أضفتها:

var service = serviceProvider.GetService<ITestService>();

لاحظ أنه لاستخدام الإصدار العام ، عليك تضمين مساحة الاسم مع الملحقات:

using Microsoft.Extensions.DependencyInjection;

ITestService.cs

public interface ITestService
{
    int GenerateRandom();
}

TestService.cs

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

Startup.cs (ConfigureServices)

public void ConfigureServices(IServiceCollection services)
{
    services.AddApplicationInsightsTelemetry(Configuration);
    services.AddMvc();

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

HomeController.cs

using Microsoft.Extensions.DependencyInjection;

namespace Core.Controllers
{
    public class HomeController : Controller
    {
        public HomeController(IServiceProvider serviceProvider)
        {
            var service = serviceProvider.GetService<ITestService>();
            int rnd = service.GenerateRandom();
        }

كيف يمكنني حل نوع يدويًا باستخدام إطار حقن التبعية المدمج في ASP.NET Core MVC؟

إعداد الحاوية سهل بما فيه الكفاية:

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

    services.AddTransient<ISomeService, SomeConcreteService>();
}

ولكن كيف يمكنني حل ISomeService دون إجراء الحقن؟ على سبيل المثال ، أريد القيام بذلك:

ISomeService service = services.Resolve<ISomeService>();

لا توجد مثل هذه الأساليب في IServiceCollection .


إذا كنت بحاجة فقط إلى حل تبعية واحدة بغرض نقلها إلى مُنشئ تبعية أخرى تقوم بالتسجيل ، يمكنك القيام بذلك.

دعنا نقول أن لديك خدمة حصلت على سلسلة وخدمة ISomeService.

public class AnotherService : IAnotherService
{
    public AnotherService(ISomeService someService, string serviceUrl)
    {
        ...
    }
}

عندما تذهب لتسجيل هذا داخل Startup.cs ، ستحتاج إلى القيام بذلك:

services.AddScoped<IAnotherService>(ctx => 
      new AnotherService(ctx.GetService<ISomeService>(), "https://someservice.com/")
);

يتم استخدام واجهة IServiceCollection لبناء حاوية حقن التبعية. بعد تكوينه بالكامل ، يتم تكوينه إلى مثيل IServiceProvider والذي يمكنك استخدامه لحل الخدمات. يمكنك حقن IServiceProvider في أي فئة. يمكن أن توفر IApplicationBuilder و HttpContext مزود الخدمة كذلك ، عبر خصائص ApplicationServices أو RequestServices على التوالي.

يعرّف IServiceProvider طريقة GetService(Type type) لحل خدمة:

var service = (IFooService)serviceProvider.GetService(typeof(IFooService));

هناك أيضًا العديد من طرق تمديد الراحة المتاحة ، مثل serviceProvider.GetService<IFooService>() (إضافة using لـ Microsoft.Extensions.DependencyInjection ).

حل الخدمات داخل فئة بدء التشغيل

حقن التبعيات

يمكن لوقت التشغيل حقن الخدمات في مُنشئ فئة Startup ، مثل IHostingEnvironment و IServiceProvider و IServiceProvider . يرجى ملاحظة أن مزود الخدمة هذا هو مثيل تم بناؤه بواسطة طبقة الاستضافة ويحتوي فقط على خدمات لبدء تشغيل التطبيق.

يمكن أيضًا حقن الخدمات في طريقة Configure() . يمكنك إضافة قائمة عشوائية من المعلمات بعد المعلمة IApplicationBuilder . يمكنك أيضًا حقن خدماتك الخاصة المسجلة بطريقة ConfigureServices() هنا ، وسيتم حلها من مزود خدمة التطبيق بدلاً من مزود خدمة الاستضافة .

public void Configure(IApplicationBuilder app, IFooService fooService)
{
   // ...
}

ومع ذلك ، لا يسمح الأسلوب ConfigureServices() خدمات الحقن) ، ولكنه يقبل وسيطة IServiceCollection فقط. هذه هي الطريقة حيث يمكنك تكوين حاوية حقن التبعية التطبيق الخاص بك. يمكنك استخدام الخدمات المحقونة في مُنشئ بدء التشغيل هنا. فمثلا:

public Startup(IConfiguration configuration)
{
    Configuration = configuration;
}

public IConfiguration Configuration { get; }

public void ConfigureServices(IServiceCollection services)
{
    // Use Configuration here
}

حل التبعيات يدويا

إذا كنت ترغب في حل الخدمات يدويًا ، فيمكنك السماح لوقت التشغيل بضخ مثيل IServiceProvider في المُنشئ أو استخدام ApplicationServices التي يوفرها IApplicationBuilder في طريقة Configure() :

public Startup(IServiceProvider serviceProvider)
{
    var hostingEnv = serviceProvider.GetService<IHostingEnvironment>();
}

أو

public void Configure(IApplicationBuilder app)
{
    var serviceProvider = app.ApplicationServices;
    var hostingEnv = serviceProvider.GetService<IHostingEnvironment>();
}

ومع ذلك ، إذا كنت بحاجة إلى حل الخدمات في طريقة ConfigureServices() ، فأنت بحاجة إلى نهج مختلف. يمكنك إنشاء IServiceProvider وسيط من مثيل IServiceCollection الذي يحتوي على الخدمات المسجلة حتى ذلك الحين:

public void ConfigureServices(IServiceCollection services)
{
    services.AddSingleton<IFooService, FooService>();

    // Build the intermediate service provider
    var sp = services.BuildServiceProvider();
    var fooService = sp.GetService<IFooService>();
}

تحتاج إلى حزمة Microsoft.Extensions.DependencyInjection لهذا الغرض.

يرجى الملاحظة:
بشكل عام ، يجب ألا تحل الخدمات داخل طريقة ConfigureServices() ، لأن هذا هو المكان الذي تقوم فيه بتكوين خدمات التطبيق. في بعض الأحيان ، تحتاج فقط إلى الوصول إلى بعض IOptions<MyOptions> . يمكنك تحقيق ذلك عن طريق ربط القيم من مثيل IConfiguration إلى مثيل MyOptions (وهو ما يفعله إطار الخيارات بشكل أساسي):

public void ConfigureServices(IServiceCollection services)
{
    var myOptions = new MyOptions();
    Configuration.GetSection("SomeSection").Bind(myOptions);
}

تُعرف خدمات حل المشكلات يدويًا ( وتعرف أيضًا باسم Service Locator) بشكل عام على أنها نمط مضاد . على الرغم من أنه يحتوي على حالات استخدام (للأطر و / أو طبقات البنية التحتية) ، إلا أنه يجب عليك تجنبها قدر الإمكان.


يمكنك حقن التبعيات في سمات مثل AuthorizeAttribute بهذه الطريقة

var someservice = (ISomeService)context.HttpContext.RequestServices.GetService(typeof(ISomeService));




asp.net-core-mvc