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

การตัดการทำงานระยะสั้นและการแตกแขนง

ใช้ MapWhen, UseWhen และมิดเดิลแวร์ปลายทางเพื่อแตกแขนงหรือยุติสายงานตามเงื่อนไขของคำขอ

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

การแยกแขนงและการหยุดก่อนถึงส่วนถัดไป

ไม่ใช่ทุกคำขอที่ควรผ่านไปป์ไลน์มิดเดิลแวร์ทั้งหมด ASP.NET Core จึงมีเครื่องมือสำหรับแยกแขนง (ส่งชุดคำขอย่อยไปยังไปป์ไลน์ที่แตกต่างกัน) และหยุดก่อนถึงส่วนถัดไป (หยุดประมวลผลแล้วส่งกลับทันที)

Map: การแยกแขนงถาวรตามเส้นทาง

Map สร้างแขนงถาวร คำขอที่ตรงกับคำนำหน้าจะเข้าสู่แขนงนั้นและจะไม่กลับมายังไปป์ไลน์หลัก

app.Map("/api", apiApp =>
{
    apiApp.UseAuthentication();
    apiApp.UseAuthorization();
    apiApp.Run(async ctx =>
        await ctx.Response.WriteAsync("API branch"));
});

// Requests to /api/... enter the branch above.
// Requests to /public/... skip the branch entirely.
app.Run(async ctx =>
    await ctx.Response.WriteAsync("Main pipeline"));

MapWhen: การแยกแขนงตามเงื่อนไข

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

// Branch when a specific header is present
app.MapWhen(
    ctx => ctx.Request.Headers.ContainsKey("X-Internal"),
    internalApp =>
    {
        internalApp.UseMiddleware<InternalApiMiddleware>();
        internalApp.Run(async ctx =>
            await ctx.Response.WriteAsync("Internal route"));
    });

// Branch on query parameter
app.MapWhen(
    ctx => ctx.Request.Query.ContainsKey("legacy"),
    legacyApp => legacyApp.UseMiddleware<LegacyHandlerMiddleware>());

UseWhen: การแยกแขนงแบบมีเงื่อนไขที่กลับมารวมกัน

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

// Log only for authenticated API calls; public routes not logged
app.UseWhen(
    ctx => ctx.Request.Path.StartsWithSegments("/api")
           && ctx.User.Identity?.IsAuthenticated == true,
    loggedApp =>
    {
        loggedApp.UseMiddleware<AuditMiddleware>();
    });

// All requests continue here after the branch
app.UseRouting();
app.MapControllers();

การหยุดไปป์ไลน์ด้วยการไม่เรียกส่วนถัดไป

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

app.Use(async (ctx, next) =>
{
    // IP allowlist check
    var ip = ctx.Connection.RemoteIpAddress?.ToString();
    var allowed = new[] { "127.0.0.1", "::1", "10.0.0.0/8" };

    if (!IsAllowed(ip, allowed))
    {
        ctx.Response.StatusCode = 403;
        await ctx.Response.WriteAsJsonAsync(
            new { error = "Access denied from this IP" });
        return; // short-circuit
    }

    await next(ctx); // proceed
});

ShortCircuit() ใน .NET 8

ใน .NET 8 MapShortCircuit และส่วนขยาย ShortCircuit() บนจุดปลายทางจะมอบเส้นทางการหยุดก่อนถึงส่วนถัดไปแบบประกาศที่ปรับให้เหมาะสมอย่างมาก

// Reject known bad paths immediately — skip entire pipeline
app.MapShortCircuit(404, "robots.txt", "favicon.ico");

// Or on a specific endpoint:
app.MapGet("/health", () => "OK")
   .ShortCircuit(); // skips auth, rate limiting, etc.

// 'Run' middleware also short-circuits:
app.Map("/old-api", old =>
    old.Run(ctx =>
    {
        ctx.Response.StatusCode = 301;
        ctx.Response.Headers.Location = "/api/v2";
        return Task.CompletedTask;
    }));

มิดเดิลแวร์สิ้นสุดเทียบกับการกำหนดเส้นทางจุดปลายทาง

ก่อน .NET 3 app.Run() เป็นตัวเลือกเดียวสำหรับการสิ้นสุด ปัจจุบันนิยมใช้การกำหนดเส้นทางจุดปลายทาง (MapGet, MapControllers) มากกว่า เพราะทำงานร่วมกับการอนุญาตสิทธิ์ การจำกัดอัตรา และเมทาดาทา

// OLD: terminal middleware
app.Run(async ctx => {
    if (ctx.Request.Path == "/ping")
        await ctx.Response.WriteAsync("pong");
});

// PREFERRED: endpoint routing
app.MapGet("/ping", () => "pong")
   .WithTags("Health")
   .AllowAnonymous()
   .RequireRateLimiting("basic");

รายละเอียดการจับคู่เส้นทาง

Map("/api") จะจับคู่กับ /api และ /api/anything เส้นทางที่จับคู่แล้วจะถูกนำออกจาก Request.Path ภายในแขนง และย้ายไปเก็บไว้ใน Request.PathBase

app.Map("/api", apiApp =>
{
    apiApp.Use(async (ctx, next) =>
    {
        // Path in branch: /users/42 (prefix removed)
        Console.WriteLine(ctx.Request.Path);     // /users/42
        Console.WriteLine(ctx.Request.PathBase); // /api
        await next(ctx);
    });
    apiApp.MapGet("/users/{id}", (int id) => id);
});

การผสานรูปแบบการแยกแขนง

แอปจริงจะผสาน Map, UseWhen และการหยุดก่อนถึงส่วนถัดไปเพื่อสร้างไปป์ไลน์หลายชั้น: เส้นทางสาธารณะมีการประมวลผลแบบเบา เส้นทาง API มีการยืนยันตัวตน และเส้นทางผู้ดูแลระบบมีการตรวจสอบเพิ่มเติม

// Public area — no auth
app.Map("/public", pub =>
{
    pub.MapGet("/health", () => "OK");
    pub.MapGet("/docs",   () => "Documentation");
});

// API area — full auth + rate limiting
app.Map("/api", api =>
{
    api.UseAuthentication();
    api.UseAuthorization();
    api.UseRateLimiter();
    api.MapControllers();
});

// Admin area — require admin role
app.Map("/admin", admin =>
{
    admin.UseAuthentication();
    admin.UseAuthorization();
    admin.MapControllers().RequireAuthorization("AdminPolicy");
});

กรณีใช้งานจริง: มิดเดิลแวร์ทดสอบแบบ A/B

มิดเดิลแวร์ทดสอบแบบ A/B จะแยกคำขอไปยังตัวจัดการที่แตกต่างกันตามคุกกี้หรือส่วนหัว โดยไม่ต้องแก้ไขโค้ดจุดปลายทาง

app.UseWhen(
    ctx => ctx.Request.Cookies.TryGetValue("ab-group", out var g) && g == "B",
    betaApp =>
    {
        betaApp.Use(async (ctx, next) =>
        {
            ctx.Items["IsGroupB"] = true;
            await next(ctx);
        });
    });

// Endpoint reads the flag:
app.MapGet("/products", (HttpContext ctx, ProductService svc) =>
{
    bool isB = ctx.Items.ContainsKey("IsGroupB");
    return isB ? svc.GetNewLayoutAsync() : svc.GetOldLayoutAsync();
});

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

ความแตกต่างที่สำคัญระหว่าง MapWhen และ UseWhen คืออะไร

สรุป: การหยุดก่อนถึงส่วนถัดไปและการแยกแขนง

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

  • Map: แขนงถาวรตามเส้นทาง (ไม่กลับมารวมกัน)
  • MapWhen: แขนงถาวรตามเงื่อนไข
  • UseWhen: แขนงแบบมีเงื่อนไขที่กลับมารวมกับไปป์ไลน์หลัก
  • การหยุดก่อนถึงส่วนถัดไป: ไม่เรียกใช้ next เขียนการตอบกลับแล้วส่งคืน
  • ShortCircuit() (.NET 8): จุดปลายทางสิ้นสุดแบบประกาศที่ปรับให้เหมาะสม
  • ผสานการแยกแขนงเพื่อสร้างไปป์ไลน์หลายชั้น: สาธารณะ / API / ผู้ดูแลระบบ

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

บทเรียน “การตัดการทำงานระยะสั้นและการแตกแขนง” ฟรีหรือไม่

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

คุณจะเรียนรู้อะไรในบทเรียน “การตัดการทำงานระยะสั้นและการแตกแขนง”

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

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

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

บทเรียน “การตัดการทำงานระยะสั้นและการแตกแขนง” ใช้เวลานานแค่ไหน

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

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

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

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

  1. ภาพรวมสายงาน ASP.NET Core
  2. การเขียนมิดเดิลแวร์แบบกำหนดเอง
  3. การตัดการทำงานระยะสั้นและการแตกแขนง
  4. ลำดับมิดเดิลแวร์และมิดเดิลแวร์ในตัว
← กลับไปที่ C# Academy