0Pricing
C# Academy · บทเรียน

อายุการใช้งานบริการ: ชั่วคราว มีขอบเขต Singleton

เรียนรู้ว่าอายุการใช้งานแบบ Transient, Scoped และ Singleton ส่งผลต่อการสร้าง การใช้ร่วมกัน และการกำจัดออบเจ็กต์อย่างไร

อายุการใช้งานบริการ: ชั่วคราว มีขอบเขต Singleton เป็นบทเรียน C# Academy ฟรีบน CoddyKit นี่คือบทเรียนที่ 2 จากทั้งหมด 4 บทเรียน คุณสามารถอ่านบทเรียนทั้งหมดด้านล่างฟรี — จากนั้นลองปฏิบัติด้วยตัวคุณเองในเบราว์เซอร์พร้อมตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7 บทเรียนนี้เป็นส่วนหนึ่งของเส้นทางการเรียน C# Academy และความก้าวหน้าของคุณจะซิงค์ข้ามเว็บและแอป CoddyKit คอร์ส C# Academy มีบทเรียนทั้งหมด 4 บทเรียน

เหตุใดอายุการใช้งานจึงสำคัญ

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

ชั่วคราว: สร้างใหม่ทุกครั้ง

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

builder.Services.AddTransient<IEmailSender, SmtpEmailSender>();

// Each resolution creates a new instance:
// var a = sp.GetRequiredService<IEmailSender>(); // new
// var b = sp.GetRequiredService<IEmailSender>(); // new (different)

ตามขอบเขต: หนึ่งครั้งต่อคำขอ

บริการแบบ ตามขอบเขต จะถูกสร้างขึ้นหนึ่งครั้งต่อ scope ซึ่งโดยทั่วไปหมายถึงคำขอ HTTP หนึ่งรายการใน ASP.NET Core อินสแตนซ์เดียวกันจะถูกใช้ร่วมกันภายในคำขอหนึ่งรายการ และจะสร้างอินสแตนซ์ใหม่สำหรับคำขอถัดไป

builder.Services.AddScoped<AppDbContext>();

// Within a single HTTP request:
// Both resolve to the SAME AppDbContext instance
// -> consistent unit of work across the request

ซิงเกิลตัน: หนึ่งอินสแตนซ์ตลอดอายุแอป

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

builder.Services.AddSingleton<IMemoryCache, MemoryCache>();

// Or register a pre-built instance:
var config = new AppConfig { MaxRetries = 3 };
builder.Services.AddSingleton<IAppConfig>(config);

เปรียบเทียบทั้งสามแบบ

เปรียบเทียบแบบเห็นภาพได้อย่างรวดเร็ว:

  • ชั่วคราว — อินสแตนซ์ใหม่ทุกคำขอ เหมาะกับยูทิลิตีที่ไม่มีสถานะ
  • ตามขอบเขต — หนึ่งอินสแตนซ์ต่อคำขอ HTTP เหมาะกับ DbContext และหน่วยงานต่อหนึ่งงาน
  • ซิงเกิลตัน — หนึ่งอินสแตนซ์ตลอดอายุแอป เหมาะกับแคชและการกำหนดค่า

ปัญหาการพึ่งพาที่ถูกกักไว้

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

// BAD: Singleton captures a Scoped service
public class MySingleton
{
    private readonly AppDbContext _db; // Scoped!
    public MySingleton(AppDbContext db) => _db = db;
    // _db is now stuck alive for the app's lifetime
}

การตรวจจับการละเมิดขอบเขต

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

builder.Host.UseDefaultServiceProvider(options =>
{
    options.ValidateScopes = true;   // detect captive deps
    options.ValidateOnBuild = true;  // fail fast at start
});

บริการแบบ Scoped นอกคำขอ

หากต้องการแก้ไขบริการแบบ Scoped ในงานเบื้องหลัง ให้สร้างขอบเขตอย่างชัดเจนโดยใช้ IServiceScopeFactory ห้ามแก้ไขบริการแบบ Scoped โดยตรงจากคอนเทนเนอร์ราก

public class MyWorker : BackgroundService
{
    private readonly IServiceScopeFactory _factory;

    public MyWorker(IServiceScopeFactory factory) => _factory = factory;

    protected override async Task ExecuteAsync(CancellationToken ct)
    {
        using var scope = _factory.CreateScope();
        var db = scope.ServiceProvider.GetRequiredService<AppDbContext>();
        await db.Users.ToListAsync(ct);
    }
}

บริการแบบ Transient ที่ปล่อยทรัพยากรได้

บริการ IDisposable แบบ Transient ที่แก้ไขจากคอนเทนเนอร์รากจะถูกติดตามจนกว่าคอนเทนเนอร์จะถูกทำลาย ซึ่งมักเกิดขึ้นตอนปิดแอป ให้แก้ไขบริการเหล่านี้ภายในขอบเขตเพื่อคืนทรัพยากรได้อย่างรวดเร็ว

// Correctly scoped transient disposable
using var scope = sp.CreateScope();
var svc = scope.ServiceProvider.GetRequiredService<MyDisposableService>();
await svc.DoWorkAsync();
// svc.Dispose() called when scope is disposed

การเลือกอายุการใช้งานที่เหมาะสม

แนวทางตัดสินใจอย่างง่าย:

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

ตัวอย่างจริง: ใช้สามอายุการใช้งานร่วมกัน

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

builder.Services.AddSingleton<IConfiguration>(builder.Configuration);
builder.Services.AddSingleton<ICacheService, RedisCacheService>();

builder.Services.AddScoped<AppDbContext>();
builder.Services.AddScoped<IOrderRepository, OrderRepository>();
builder.Services.AddScoped<OrderService>();

builder.Services.AddTransient<IEmailSender, SendGridEmailSender>();

ตรวจสอบความเข้าใจ

จะเกิดปัญหาใดขึ้นเมื่อบริการแบบซิงเกิลตันเก็บการอ้างอิงไปยังบริการแบบตามขอบเขต

ทบทวน: อายุการใช้งานของบริการ

ประเด็นสำคัญ:

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

คำถามที่พบบ่อย

บทเรียน “อายุการใช้งานบริการ: ชั่วคราว มีขอบเขต Singleton” ฟรีหรือไม่

ใช่ — ข้อความเต็มของ “อายุการใช้งานบริการ: ชั่วคราว มีขอบเขต Singleton” ฟรีให้อ่านที่นี่บนเว็บ เพื่อปฏิบัติแบบโต้ตอบ (ตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7) และปลดล็อคส่วนที่เหลือของคอร์ส C# Academy ให้อัปเกรดเป็น CoddyKit PRO คอร์ส C# Academy มีบทเรียนทั้งหมด 4 บทเรียน

คุณจะเรียนรู้อะไรในบทเรียน “อายุการใช้งานบริการ: ชั่วคราว มีขอบเขต Singleton”

เรียนรู้ว่าอายุการใช้งานแบบ Transient, Scoped และ Singleton ส่งผลต่อการสร้าง การใช้ร่วมกัน และการกำจัดออบเจ็กต์อย่างไร คุณปฏิบัติ C# Academy ด้วยโค้ดที่ใช้งานได้จริงที่คุณเรียกใช้โดยตรงในเบราว์เซอร์ และติวเตอร์ AI ตลอด 24/7 ตอบคำถามของคุณขณะที่คุณไปผ่านบทเรียน

คุณต้องมีประสบการณ์ก่อนที่จะเริ่มเรียน C# Academy หรือไม่

ไม่จำเป็นต้องมีประสบการณ์มาก่อน C# Academy บน CoddyKit ออกแบบมาสำหรับผู้เริ่มต้นไปจนถึงผู้เรียนขั้นสูง คุณสามารถเริ่มต้นที่นี่หรือเริ่มจากตัวแรกและเรียนด้วยความเร็วของคุณเอง นี่คือบทเรียนที่ 2 จากทั้งหมด 4 บทเรียน

บทเรียน “อายุการใช้งานบริการ: ชั่วคราว มีขอบเขต Singleton” ใช้เวลานานแค่ไหน

บทเรียน CoddyKit ส่วนใหญ่ใช้เวลาประมาณ 5–10 นาที แต่ละบทเรียนจึงสั้นและเป็นแบบโต้ตอบ คุณสามารถก้าวหน้าอย่างต่อเนื่องและกลับมาเรียนต่อจากตรงที่เพิ่งหยุดบนเว็บและแอปได้เลย

ฉันเขียนและรันโค้ดในบทเรียน C# Academy นี้ได้ไหม

ได้ บทเรียน C# Academy ทุกบทมีตัวแก้ไขโค้ดในตัว คุณจึงเขียนและรันโค้ดจริงได้เลยในเบราว์เซอร์ และได้รับข้อเสนอแนะจาก AI ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ

บทเรียนทั้งหมดในหลักสูตรนี้

  1. พื้นฐานคอนเทนเนอร์ DI
  2. อายุการใช้งานบริการ: ชั่วคราว มีขอบเขต Singleton
  3. การฉีดผ่าน Constructor และอินเทอร์เฟซ
  4. รูปแบบ Factory และ Options
← กลับไปที่ C# Academy