ความแตกต่างของ AddTransient, AddScoped และ AddSingleton


937

ฉันต้องการติดตั้งระบบฉีดพึ่งพา (DI) ใน ASP.NET Core ดังนั้นหลังจากเพิ่มรหัสนี้ในConfigureServicesวิธีการทั้งสองวิธีทำงาน

ความแตกต่างระหว่างservices.AddTransientและservice.AddScopedวิธีการใน ASP.NET Core คืออะไร?

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

    // Add application services.
    services.AddTransient<IEmailSender, AuthMessageSender>();
    services.AddScoped<IEmailSender, AuthMessageSender>();
}

92
@tmg เอกสารบอกว่า 'บริการตลอดชีพชั่วคราวถูกสร้างขึ้นทุกครั้งที่มีการร้องขอ' และ 'บริการตลอดช่วงอายุที่กำหนดจะถูกสร้างขึ้นหนึ่งครั้งต่อคำขอ' ซึ่งนอกจากความเข้าใจภาษาอังกฤษของฉันจะอ่อนแอกว่าที่ฉันคิดจริง ๆ แล้วหมายถึงสิ่งเดียวกันแน่นอน
Neutrino

70
@tmg ฉันรู้ ฉันแค่ชี้ให้เห็นว่าเอกสารไม่ชัดเจนเลยในจุดนี้ดังนั้นการชี้ผู้คนไปยังเอกสารนั้นไม่ได้มีประโยชน์มาก
ตริโน

13
@ Neutrino นั่นคือเหตุผลที่ฉันถามคำถามนี้
Elvin Mammadov

5
ไปงานปาร์ตี้อ่านความคิดเห็นในภายหลัง แต่ฉันพิมพ์บทความนั้นออกมาอ่านและจดจ่อกับการสังเกตแบบเดิมที่ฉันเห็น @Nutrino ทำที่นี่ บทความนี้มีความคลุมเครือทั้งหมดในการนำเสนอการวิเคราะห์ ตัวอย่างโชคดีที่ทำให้สับสนน้อยลง
Wellspring

5
เท่าที่ผมเข้าใจบริการอายุการใช้งานชั่วคราวที่ถูกสร้างขึ้นในแต่ละครั้งที่พวกเขาจะได้รับการร้องขอ คำที่ร้องขอที่นี่คือความหมายภาษาอังกฤษทุกวันของการขอบางสิ่งบางอย่างในกรณีนี้บริการ ในขณะที่คำขอคำในครั้งเดียวต่อคำขอหมายถึงคำขอ HTTP แต่ฉันเข้าใจความรู้สึกสับสน
Memet Olsen

คำตอบ:


1649

TL; DR

วัตถุชั่วคราวนั้นแตกต่างกันเสมอ มีการให้อินสแตนซ์ใหม่ให้กับทุกคอนโทรลเลอร์และทุกบริการ

วัตถุที่ถูกกำหนดขอบเขตจะเหมือนกันภายในคำขอ แต่ต่างกันไปตามคำขอที่ต่างกัน

วัตถุ Singleton เหมือนกันสำหรับทุกวัตถุและทุกคำขอ

สำหรับการชี้แจงเพิ่มเติมตัวอย่างจากเอกสารคู่มือASP.NETแสดงความแตกต่าง:

OperationIdแสดงให้เห็นถึงความแตกต่างระหว่างอายุการใช้งานและการลงทะเบียนตัวเลือกเหล่านี้ให้พิจารณาอินเตอร์เฟซที่เรียบง่ายที่แสดงถึงหนึ่งหรือมากกว่าหนึ่งงานการดำเนินงานที่มีตัวบ่งชี้ที่ไม่ซ้ำกัน ขึ้นอยู่กับวิธีที่เรากำหนดค่าอายุการใช้งานสำหรับบริการนี้คอนเทนเนอร์จะให้อินสแตนซ์ของบริการที่เหมือนกันหรือแตกต่างกันในคลาสที่ร้องขอ เพื่อให้ชัดเจนว่าจะขออายุการใช้งานเท่าใดเราจะสร้างตัวเลือกหนึ่งประเภทต่ออายุการใช้งาน:

using System;

namespace DependencyInjectionSample.Interfaces
{
    public interface IOperation
    {
        Guid OperationId { get; }
    }

    public interface IOperationTransient : IOperation
    {
    }

    public interface IOperationScoped : IOperation
    {
    }

    public interface IOperationSingleton : IOperation
    {
    }

    public interface IOperationSingletonInstance : IOperation
    {
    }
}

เราใช้อินเทอร์เฟซเหล่านี้โดยใช้คลาสเดียวOperationที่ยอมรับ GUID ในตัวสร้างหรือใช้ GUID ใหม่หากไม่มีการจัดเตรียมไว้ให้:

using System;
using DependencyInjectionSample.Interfaces;
namespace DependencyInjectionSample.Classes
{
    public class Operation : IOperationTransient, IOperationScoped, IOperationSingleton, IOperationSingletonInstance
    {
        Guid _guid;
        public Operation() : this(Guid.NewGuid())
        {

        }

        public Operation(Guid guid)
        {
            _guid = guid;
        }

        public Guid OperationId => _guid;
    }
}

ถัดไปในConfigureServicesแต่ละประเภทจะถูกเพิ่มลงในภาชนะบรรจุตามอายุการใช้งานที่ตั้งชื่อ:

services.AddTransient<IOperationTransient, Operation>();
services.AddScoped<IOperationScoped, Operation>();
services.AddSingleton<IOperationSingleton, Operation>();
services.AddSingleton<IOperationSingletonInstance>(new Operation(Guid.Empty));
services.AddTransient<OperationService, OperationService>();

โปรดทราบว่าIOperationSingletonInstanceบริการกำลังใช้อินสแตนซ์ที่เฉพาะเจาะจงที่มี ID ที่รู้จักGuid.Emptyดังนั้นจะมีความชัดเจนเมื่อใช้งานประเภทนี้ นอกจากนี้เรายังได้ลงทะเบียนรายการOperationServiceที่ขึ้นอยู่กับOperationประเภทอื่น ๆเพื่อให้ชัดเจนภายในคำขอว่าบริการนี้ได้รับอินสแตนซ์เดียวกับคอนโทรลเลอร์หรือใหม่สำหรับแต่ละประเภทการดำเนินการ บริการทั้งหมดนี้จะเปิดเผยการพึ่งพาเป็นคุณสมบัติเพื่อให้สามารถแสดงในมุมมอง

using DependencyInjectionSample.Interfaces;

namespace DependencyInjectionSample.Services
{
    public class OperationService
    {
        public IOperationTransient TransientOperation { get; }
        public IOperationScoped ScopedOperation { get; }
        public IOperationSingleton SingletonOperation { get; }
        public IOperationSingletonInstance SingletonInstanceOperation { get; }

        public OperationService(IOperationTransient transientOperation,
            IOperationScoped scopedOperation,
            IOperationSingleton singletonOperation,
            IOperationSingletonInstance instanceOperation)
        {
            TransientOperation = transientOperation;
            ScopedOperation = scopedOperation;
            SingletonOperation = singletonOperation;
            SingletonInstanceOperation = instanceOperation;
        }
    }
}

แสดงให้เห็นถึงชีวิตวัตถุภายในและระหว่างแต่ละคำขอแยกต่างหากเพื่อการประยุกต์ใช้กลุ่มตัวอย่างมีOperationsControllerการร้องขอชนิดของแต่ละประเภทเช่นเดียวกับIOperation OperationServiceการIndexกระทำนั้นจะแสดงค่าของตัวควบคุมและบริการOperationIdทั้งหมด

using DependencyInjectionSample.Interfaces;
using DependencyInjectionSample.Services;
using Microsoft.AspNetCore.Mvc;

namespace DependencyInjectionSample.Controllers
{
    public class OperationsController : Controller
    {
        private readonly OperationService _operationService;
        private readonly IOperationTransient _transientOperation;
        private readonly IOperationScoped _scopedOperation;
        private readonly IOperationSingleton _singletonOperation;
        private readonly IOperationSingletonInstance _singletonInstanceOperation;

        public OperationsController(OperationService operationService,
            IOperationTransient transientOperation,
            IOperationScoped scopedOperation,
            IOperationSingleton singletonOperation,
            IOperationSingletonInstance singletonInstanceOperation)
        {
            _operationService = operationService;
            _transientOperation = transientOperation;
            _scopedOperation = scopedOperation;
            _singletonOperation = singletonOperation;
            _singletonInstanceOperation = singletonInstanceOperation;
        }

        public IActionResult Index()
        {
            // ViewBag contains controller-requested services
            ViewBag.Transient = _transientOperation;
            ViewBag.Scoped = _scopedOperation;
            ViewBag.Singleton = _singletonOperation;
            ViewBag.SingletonInstance = _singletonInstanceOperation;

            // Operation service has its own requested services
            ViewBag.Service = _operationService;
            return View();
        }
    }
}

ตอนนี้มีการร้องขอแยกกันสองคำขอสำหรับการกระทำของคอนโทรลเลอร์นี้:

คำขอแรก

คำขอที่สอง

สังเกตว่าOperationIdค่าใดที่เปลี่ยนแปลงไปในคำขอและระหว่างคำขอ

  • วัตถุชั่วคราวนั้นแตกต่างกันเสมอ มีการให้อินสแตนซ์ใหม่ให้กับทุกคอนโทรลเลอร์และทุกบริการ

  • วัตถุที่ถูกกำหนดขอบเขตจะเหมือนกันภายในคำขอ แต่ต่างกันไปตามคำขอที่ต่างกัน

  • วัตถุ Singleton เหมือนกันสำหรับทุกวัตถุและทุกคำขอ (ไม่ว่าจะมีอินสแตนซ์ให้หรือไม่ConfigureServices)


14
ฉันเข้าใจฟังก์ชั่นของแต่ละคน แต่คนอื่นสามารถอธิบายถึงผลกระทบของการใช้อันใดอันหนึ่งแทนการใช้แบบอื่น ปัญหาอะไรที่อาจทำให้เกิดหากไม่ได้ใช้อย่างถูกต้องหรือเลือกอย่างอื่นแทน
pawan nepal

2
สมมติว่าคุณกำลังสร้างวัตถุที่เกี่ยวข้องกับคำขอบริบท (เช่นผู้ใช้ปัจจุบัน) ที่มีขอบเขตเดี่ยวแล้วมันจะยังคงเป็นอินสแตนซ์เดียวกันกับคำขอ HTTP ทั้งหมดที่ไม่ต้องการ IOC คือทั้งหมดที่เกี่ยวกับการสร้างอินสแตนซ์ดังนั้นเราจำเป็นต้องระบุขอบเขตของอินสแตนซ์ที่สร้างขึ้น
akazemis

1
มันคือ! ฉันได้พูดถึงลิงค์ที่ด้านบนของหัวข้อ! โค้ดตัวอย่างคือการคัดลอก / วางจาก MS docs
akazemis

1
ขอบคุณ ใช่จะเป็นแบบเดียวกันตลอดทั้งแอปโดยไม่คำนึงถึงเซสชัน / ผู้ใช้ เห็นได้ชัดว่าหากแอปของคุณใช้สถาปัตยกรรมไมโครไซต์และบริการแต่ละบริการทำงานในกระบวนการที่แยกต่างหากซิงเกิลจะเหมือนกันในแต่ละกระบวนการ
akazemis

1
คุณช่วยยกตัวอย่างการใช้ addTransient ให้เราได้ไหม เพราะฉันไม่พบสาธารณูปโภคใด ๆ ให้ใช้ในขณะที่ใช้ทรัพยากรมากเกินไป
Terai

318

ใน. NET การฉีดพึ่งพามีสามอายุการใช้งานที่สำคัญ:

Singletonซึ่งสร้างอินสแตนซ์เดียวตลอดทั้งแอปพลิเคชัน มันจะสร้างอินสแตนซ์เป็นครั้งแรกและนำวัตถุเดียวกันมาใช้ใหม่ในการโทรทั้งหมด

บริการอายุการใช้งานที่กำหนดขอบเขตจะถูกสร้างขึ้นหนึ่งครั้งต่อคำขอภายในขอบเขต มันเทียบเท่ากับซิงเกิลตันในขอบเขตปัจจุบัน ตัวอย่างเช่นใน MVC จะสร้างหนึ่งอินสแตนซ์สำหรับแต่ละคำขอ HTTP แต่จะใช้อินสแตนซ์เดียวกันในการโทรอื่น ๆ ภายในคำขอเว็บเดียวกัน

บริการอายุการใช้งานชั่วคราวจะถูกสร้างขึ้นทุกครั้งที่มีการร้องขอ อายุการใช้งานนี้ทำงานได้ดีที่สุดสำหรับบริการน้ำหนักเบาและไร้สัญชาติ

ที่นี่คุณสามารถค้นหาและตัวอย่างเพื่อดูความแตกต่าง:

ASP.NET 5 MVC6 การพึ่งพาการฉีดใน 6 ขั้นตอน (ลิงก์เก็บถาวรบนเว็บเนื่องจากลิงก์ตาย)

การพึ่งพาการฉีดของคุณพร้อม ASP.NET: ASP.NET 5

และนี่คือลิงค์ไปยังเอกสารอย่างเป็นทางการ:

การฉีดพึ่งพาใน ASP.NET Core


22
คุณช่วยอธิบายได้ไหมว่าทำไม Transient ถึงมีน้ำหนักเบาที่สุด? ฉันคิดว่า Transient เป็นงานที่หนักที่สุดเพราะมันต้องการสร้างตัวอย่างทุกครั้งสำหรับการฉีดทุกครั้ง
ผู้เชี่ยวชาญต้องการเป็น

17
คุณถูก. ชั่วคราวไม่ได้มีน้ำหนักเบาที่สุดผมก็บอกว่ามันเหมาะสำหรับการให้บริการที่มีน้ำหนักเบาสงบ :)
akazemis

3
ดังนั้นในสถานการณ์ที่เราสามารถใช้ scoped และใน transient ในตัวอย่างคอนโทรลเลอร์ได้เช่นถ้าเราดึงข้อมูลไม่กี่แถวจากฐานข้อมูล? ฉันพยายามที่จะเข้าใจสถานการณ์การใช้งาน scoped vs transient ในกรณีนี้
อาจารย์

4
มันขึ้นอยู่กับตรรกะที่คุณคาดหวัง ตัวอย่างเช่นถ้ามันเป็น db ตัวเดียวที่จริงแล้วมันไม่ได้สร้างความแตกต่างที่คุณใช้ แต่ถ้าคุณเรียก db หลาย ๆ ครั้งในคำขอเดียวกันคุณสามารถใช้ scoped ตลอดชีวิตเนื่องจากมันเก็บวัตถุเก็บข้อมูลเดียวกันในหน่วยความจำและนำมาใช้ซ้ำหลายครั้งภายในบริบทคำขอ Http เดียวกัน ในขณะที่หนึ่งชั่วคราวสร้างวัตถุที่เก็บใหม่หลายครั้ง (และใช้หน่วยความจำเพิ่มเติม) หากคุณอธิบายสถานการณ์เฉพาะของคุณมันจะเป็นการง่ายที่จะตัดสินว่าอันไหนที่เหมาะกว่า
akazemis

2
จุดสำคัญหนึ่งที่จะเน้นที่นี่คือ Singleton, Scoped และ Transient นั้นเหมือนกับ doills ของรัสเซียและอีกจุดหนึ่งอยู่ภายใน มันเป็นไปไม่ได้ที่จะกลับคำสั่งของพวกเขาเมื่อทำรังเช่น ไม่สามารถกำหนดขอบเขตหรือเดี่ยวใน Transient ได้เพราะเราจะขยายอายุการใช้งานของผู้ปกครองที่ต่อต้านการกักกัน!
DL Narasimhan

34

Transient, scoped และ singleton กำหนดกระบวนการสร้างวัตถุใน ASP.NET MVC core DI เมื่อต้องฉีดหลาย ๆ วัตถุในประเภทเดียวกัน ในกรณีที่คุณยังใหม่กับการฉีดคุณสามารถดูวิดีโอDI IoCนี้

คุณสามารถดูรหัสคอนโทรลเลอร์ด้านล่างซึ่งฉันได้ขออินสแตนซ์ "IDal" สองรายการในตัวสร้าง Transient, Scoped และ Singleton กำหนดว่าอินสแตนซ์เดียวกันจะถูกฉีดใน "_dal" และ "_dal1" หรือแตกต่างกัน

public class CustomerController : Controller
{
    IDal dal = null;

    public CustomerController(IDal _dal,
                              IDal _dal1)
    {
        dal = _dal;
        // DI of MVC core
        // inversion of control
    }
}

ชั่วคราว: ในอินสแตนซ์ชั่วคราวอินสแตนซ์ของวัตถุใหม่จะถูกฉีดในคำขอและการตอบสนองเดียว ด้านล่างเป็นภาพสแน็ปช็อตที่ฉันแสดงค่า GUID

ป้อนคำอธิบายภาพที่นี่

กำหนดขอบเขต: ในขอบเขตวัตถุอินสแตนซ์ของวัตถุเดียวกันจะถูกฉีดเข้าในคำขอและการตอบกลับเดียว

ป้อนคำอธิบายภาพที่นี่

Singleton: ใน singleton วัตถุเดียวกันจะถูกฉีดเข้ากับคำร้องขอและการตอบกลับทั้งหมด ในกรณีนี้หนึ่งอินสแตนซ์ส่วนกลางของวัตถุจะถูกสร้างขึ้น

ด้านล่างเป็นแผนภาพง่าย ๆ ที่อธิบายพื้นฐานข้างต้นที่มองเห็นได้

ภาพ MVC DI

ภาพด้านบนถูกดึงโดยทีมงาน SBSS เมื่อฉันได้รับการฝึกอบรม ASP.NET MVC ในมุมไบ ขอขอบคุณเป็นอย่างยิ่งไปยังทีม SBSS สำหรับการสร้างภาพด้านบน


9
นี่คือคำอธิบายเดียวที่ซับซ้อนที่สุดของบริการชั่วคราวที่ฉันเคยเห็น Transient = new TServiceเวลาที่บริการนี้ได้รับการแก้ไขเป็นเทียบเท่าของการกำหนดตัวแปรของคุณ การกำหนดขอบเขตจะแคชการเริ่มต้นครั้งแรกสำหรับ "ขอบเขต" นั้น (คำขอ HTTP ในกรณีส่วนใหญ่) Singleton จะแคชเพียงหนึ่งอินสแตนซ์ตลอดอายุการใช้งานของแอปพลิเคชัน Simple as แผนภาพข้างต้นมีความซับซ้อน
Mardoxx

2
ดังนั้นฉันคิดว่าฉันจะทำให้มันง่ายขึ้นด้วยไดอะแกรมและสแน็ปช็อตของรหัส :-) แต่ฉันเข้าใจประเด็นของคุณ
Shivprasad Koirala

30
  • Singleton เป็นอินสแตนซ์เดียวสำหรับอายุการใช้งานของโดเมนแอปพลิเคชัน
  • Scoped เป็นอินสแตนซ์เดียวสำหรับช่วงเวลาของการร้องขอ scoped ซึ่งหมายถึงการร้องขอHTTPใน ASP.NET
  • Transient เป็นอินสแตนซ์เดียวต่อคำขอรหัส

โดยปกติการร้องขอรหัสควรทำผ่านพารามิเตอร์ตัวสร้างเช่นเดียวกับใน

public MyConsumingClass(IDependency dependency)

ฉันต้องการชี้ให้เห็นในคำตอบของ @ akazemis ว่า "บริการ" ในบริบทของ DI ไม่ได้หมายความถึงบริการที่สงบ บริการเป็นการใช้งานของการอ้างอิงที่ให้การทำงาน


16

AddSingleton ()

AddSingleton () สร้างอินสแตนซ์เดียวของบริการเมื่อมีการร้องขอครั้งแรกและนำอินสแตนซ์เดียวกันนั้นกลับมาใช้ใหม่ในสถานที่ทั้งหมดที่จำเป็นต้องใช้บริการ

AddScoped ()

ในบริการที่กำหนดขอบเขตทุกคำขอ HTTP เราจะได้รับอินสแตนซ์ใหม่ อย่างไรก็ตามภายในคำขอ HTTP เดียวกันหากต้องการบริการในหลายสถานที่เช่นในมุมมองและในตัวควบคุมอินสแตนซ์เดียวกันจะมีให้สำหรับขอบเขตทั้งหมดของคำขอ HTTP นั้น แต่คำขอ HTTP ใหม่ทุกครั้งจะได้รับอินสแตนซ์ใหม่ของบริการ

AddTransient ()

ด้วยบริการชั่วคราวมีการสร้างอินสแตนซ์ใหม่ทุกครั้งที่มีการร้องขออินสแตนซ์ของบริการไม่ว่าจะอยู่ในขอบเขตของคำขอ HTTP เดียวกันหรือข้ามคำขอ HTTP อื่น


5

หลังจากมองหาคำตอบสำหรับคำถามนี้ฉันพบคำอธิบายที่ยอดเยี่ยมพร้อมตัวอย่างที่ฉันต้องการแบ่งปันกับคุณ

คุณสามารถดูวิดีโอที่แสดงความแตกต่างได้ที่นี่

ในตัวอย่างนี้เราได้รับรหัสนี้:

public interface IEmployeeRepository
{
    IEnumerable<Employee> GetAllEmployees();
    Employee Add(Employee employee);
}

public class Employee
{
    public int Id { get; set; }
    public string Name { get; set; }
}

public class MockEmployeeRepository : IEmployeeRepository
{
    private List<Employee> _employeeList;

    public MockEmployeeRepository()
    {
        _employeeList = new List<Employee>()
    {
        new Employee() { Id = 1, Name = "Mary" },
        new Employee() { Id = 2, Name = "John" },
        new Employee() { Id = 3, Name = "Sam" },
    };
    }

    public Employee Add(Employee employee)
    {
        employee.Id = _employeeList.Max(e => e.Id) + 1;
        _employeeList.Add(employee);
        return employee;
    }

    public IEnumerable<Employee> GetAllEmployees()
    {
        return _employeeList;
    }
}

HomeController

public class HomeController : Controller
{
    private IEmployeeRepository _employeeRepository;

    public HomeController(IEmployeeRepository employeeRepository)
    {
        _employeeRepository = employeeRepository;
    }

    [HttpGet]
    public ViewResult Create()
    {
        return View();
    }

    [HttpPost]
    public IActionResult Create(Employee employee)
    {
        if (ModelState.IsValid)
        {
            Employee newEmployee = _employeeRepository.Add(employee);
        }

        return View();
    }
}

สร้างมุมมอง

@model Employee
@inject IEmployeeRepository empRepository

<form asp-controller="home" asp-action="create" method="post">
    <div>
        <label asp-for="Name"></label>
        <div>
            <input asp-for="Name">
        </div>
    </div>

    <div>
        <button type="submit">Create</button>
    </div>

    <div>
        Total Employees Count = @empRepository.GetAllEmployees().Count().ToString()
    </div>
</form>

Startup.cs

public void ConfigureServices(IServiceCollection services)
{
    services.AddMvc();
    services.AddSingleton<IEmployeeRepository, MockEmployeeRepository>();
}

คัดลอกโค้ดนี้และกดปุ่มสร้างในมุมมองและสลับระหว่าง AddSingleton, AddScopedและAddTransientคุณจะได้รับในแต่ละครั้งผลที่แตกต่างกันที่จะอาจจะช่วยให้คุณเข้าใจคำอธิบายนี้:

AddSingleton () - ตามชื่อที่แสดงวิธี AddSingleton () สร้างบริการ Singleton บริการ Singleton ถูกสร้างขึ้นเมื่อมีการร้องขอครั้งแรก อินสแตนซ์เดียวกันนี้จะถูกใช้โดยคำขอที่ตามมาทั้งหมด ดังนั้นโดยทั่วไปแล้วบริการ Singleton ถูกสร้างขึ้นเพียงครั้งเดียวต่อแอปพลิเคชันและอินสแตนซ์เดียวนั้นจะถูกใช้ตลอดอายุการใช้งานของแอปพลิเคชัน

AddTransient () - วิธีนี้จะสร้างบริการชั่วคราว อินสแตนซ์ใหม่ของบริการชั่วคราวถูกสร้างขึ้นทุกครั้งที่มีการร้องขอ

AddScoped () - วิธีนี้จะสร้างบริการ Scoped อินสแตนซ์ใหม่ของบริการ Scoped ถูกสร้างขึ้นหนึ่งครั้งต่อคำขอภายในขอบเขต ตัวอย่างเช่นในเว็บแอปพลิเคชันจะสร้าง 1 อินสแตนซ์ต่อคำขอ http แต่ละรายการ แต่ใช้อินสแตนซ์เดียวกันในการโทรอื่น ๆ ภายในคำขอเว็บเดียวกันนั้น


2

ใช้อันไหนดี

ชั่วคราว

  • เนื่องจากสร้างขึ้นทุกครั้งที่พวกเขาจะใช้หน่วยความจำและทรัพยากรมากขึ้นและสามารถมีผลกระทบด้านลบต่อประสิทธิภาพ
  • ใช้สิ่งนี้สำหรับบริการน้ำหนักเบาที่มีสถานะน้อยหรือไม่มีเลย

ขอบเขต

  • ตัวเลือกที่ดีกว่าเมื่อคุณต้องการรักษาสถานะภายในคำขอ

ซิงเกิล

  • การรั่วไหลของหน่วยความจำในบริการเหล่านี้จะสร้างขึ้นเมื่อเวลาผ่านไป
  • หน่วยความจำยังมีประสิทธิภาพตามที่สร้างขึ้นเมื่อนำมาใช้ใหม่ทุกที่

ใช้ Singletons ที่คุณต้องการดูแลสถานะแอปพลิเคชันให้กว้าง การกำหนดค่าแอปพลิเคชันหรือพารามิเตอร์, บริการบันทึก, การแคชข้อมูลเป็นตัวอย่างบางส่วนที่คุณสามารถใช้ซิงเกิล

บริการฉีดด้วยอายุการใช้งานที่แตกต่างกันในอีก

  1. อย่าฉีดบริการ Scoped & Transient ลงในบริการ Singleton (สิ่งนี้จะแปลงบริการชั่วคราวหรือขอบเขตที่มีประสิทธิภาพเป็นซิงเกิล)
  2. ห้ามฉีดบริการชั่วคราวลงในบริการที่กำหนดขอบเขต ( บริการนี้จะแปลงบริการชั่วคราวไปเป็นขอบเขต)

นี่คือคำตอบที่ดีที่สุด ฉันชอบส่วนที่คุณให้ตัวอย่าง ไม่ยากที่จะเข้าใจวิธีการทำงาน มันเป็นวิธีที่ยากกว่าที่จะคิดว่าบริการใดที่จะวางและอย่างไรและเมื่อทำความสะอาดหน่วยความจำของพวกเขา มันจะดีถ้าคุณอธิบายเพิ่มเติมเกี่ยวกับเรื่องนั้น
วาเลนไทน์ที่

1

ตามที่อธิบายไว้ที่นี่ (ลิงก์นี้มีประโยชน์มาก) พร้อมตัวอย่าง

การแมประหว่างอินเทอร์เฟซและชนิดที่เป็นรูปธรรมนี้กำหนดว่าทุกครั้งที่คุณร้องขอประเภทของ IContryService คุณจะได้รับอินสแตนซ์ใหม่ของ CountryService นี่คือความหมายชั่วคราวในกรณีนี้ คุณยังสามารถเพิ่มการแมปเดี่ยว (โดยใช้ AddSingleton) และการแมปที่กำหนดขอบเขต (โดยใช้ AddScoped) การกำหนดขอบเขตในกรณีนี้หมายถึงการกำหนดขอบเขตให้กับคำขอ HTTP ซึ่งหมายความว่าเป็นแบบซิงเกิลในขณะที่คำขอปัจจุบันกำลังทำงาน คุณยังสามารถเพิ่มอินสแตนซ์ที่มีอยู่ให้กับคอนเทนเนอร์ DI โดยใช้เมธอด AddInstance นี่เป็นวิธีที่เกือบสมบูรณ์ในการลงทะเบียนกับ IServiceCollection


1

ความแตกต่างระหว่าง AddSingleton กับ AddScoped กับ AddTransient

บริการลงทะเบียน

แกน ASP.NET ให้วิธีการ 3 ต่อไปนี้เพื่อลงทะเบียนบริการกับคอนเทนเนอร์การฉีดพึ่งพา วิธีการที่เราใช้กำหนดอายุการใช้งานของบริการที่ลงทะเบียน

AddSingleton () -ตามชื่อที่แสดงวิธี AddSingleton () สร้างบริการ Singleton บริการ Singleton ถูกสร้างขึ้นเมื่อมีการร้องขอครั้งแรก อินสแตนซ์เดียวกันนี้จะถูกใช้โดยคำขอที่ตามมาทั้งหมด ดังนั้นโดยทั่วไปแล้วบริการ Singleton ถูกสร้างขึ้นเพียงครั้งเดียวต่อแอปพลิเคชันและอินสแตนซ์เดียวนั้นจะถูกใช้ตลอดอายุการใช้งานของแอปพลิเคชัน

AddTransient () -วิธีนี้จะสร้างบริการชั่วคราว อินสแตนซ์ใหม่ของบริการชั่วคราวถูกสร้างขึ้นทุกครั้งที่มีการร้องขอ

AddScoped () -วิธีนี้จะสร้างบริการ Scoped อินสแตนซ์ใหม่ของบริการ Scoped ถูกสร้างขึ้นหนึ่งครั้งต่อคำขอภายในขอบเขต ตัวอย่างเช่นในเว็บแอปพลิเคชันจะสร้าง 1 อินสแตนซ์ต่อคำขอ http แต่ละรายการ แต่ใช้อินสแตนซ์เดียวกันในการโทรอื่น ๆ ภายในคำขอเว็บเดียวกันนั้น

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.