25 คำถามสัมภาษณ์งาน ASP.NET Core ที่ต้องรู้: Middleware, DI และ Minimal APIs
รวมคำถามสัมภาษณ์งาน ASP.NET Core ที่สำคัญ ครอบคลุม Middleware, Dependency Injection และ Minimal APIs พร้อมตัวอย่างโค้ดและคำอธิบายโดยละเอียด

คำถามสัมภาษณ์งาน ASP.NET Core เกี่ยวกับ middleware, dependency injection และ minimal APIs ยังคงเป็นหัวข้อที่พบบ่อยที่สุดในการสัมภาษณ์ทางเทคนิคด้าน .NET ไม่ว่าตำแหน่งจะเน้นด้าน backend หรือ full-stack .NET ผู้สัมภาษณ์มักจะทดสอบความเข้าใจเกี่ยวกับ request pipeline, service lifetime และ API model แบบ lightweight ที่เริ่มใช้ตั้งแต่ .NET 6 และปรับปรุงต่อเนื่องจนถึง .NET 10
ลำดับของ middleware pipeline, ปัญหาความไม่ตรงกันของ DI lifetime (ปัญหา captive dependency) และความสามารถในการอธิบาย trade-off ระหว่าง minimal APIs กับ controllers เป็นสามหัวข้อหลักที่มักถูกถามในการสัมภาษณ์งาน ASP.NET Core ระดับ mid-to-senior
คำถามเกี่ยวกับ Middleware Pipeline ของ ASP.NET Core
1. Middleware ใน ASP.NET Core คืออะไร?
Middleware คือส่วนประกอบที่ถูกประกอบเข้าไปใน pipeline ของแอปพลิเคชันเพื่อจัดการ request และ response แต่ละ middleware สามารถเลือกส่ง request ต่อไปยังส่วนประกอบถัดไปหรือ short-circuit pipeline ได้ Middleware ทำงานตามลำดับที่ลงทะเบียนใน Program.cs และ response จะเดินทางกลับผ่านส่วนประกอบเดียวกันในลำดับย้อนกลับ
2. ลำดับการทำงานของ middleware ทำงานอย่างไร?
ลำดับของการเรียก app.Use*() ใน Program.cs กำหนดลำดับการทำงานที่แน่นอน Request จะไหลจากบนลงล่างผ่าน middleware แต่ละตัว และ response จะไหลจากล่างขึ้นบน นี่คือเหตุผลที่ UseAuthentication() ต้องอยู่ก่อน UseAuthorization() และ UseRouting() ต้องอยู่ก่อน UseEndpoints()
var app = builder.Build();
app.UseExceptionHandler("/error"); // 1. Outermost: catches all exceptions
app.UseHsts(); // 2. HTTP Strict Transport Security
app.UseHttpsRedirection(); // 3. Redirect HTTP to HTTPS
app.UseStaticFiles(); // 4. Serve static files (short-circuits if found)
app.UseRouting(); // 5. Match request to endpoint
app.UseAuthentication(); // 6. Identify the user
app.UseAuthorization(); // 7. Check permissions
app.MapControllers(); // 8. Execute the matched endpoint
app.Run();การวาง UseStaticFiles() ก่อน authentication ช่วยหลีกเลี่ยงการตรวจสอบ auth ที่ไม่จำเป็นสำหรับไฟล์ CSS, JS และรูปภาพ ซึ่งมักเป็นคำถามต่อเนื่องในการสัมภาษณ์
3. วิธีเขียน custom middleware เป็นอย่างไร?
Custom middleware สามารถสร้างได้ในรูปแบบ class ที่มี method InvokeAsync หรือใช้ inline ผ่าน app.Use() แนวทางแบบ class เป็นที่นิยมสำหรับโค้ด production เนื่องจากรองรับ dependency injection ผ่าน parameter ของ constructor
public class RequestTimingMiddleware
{
private readonly RequestDelegate _next;
private readonly ILogger<RequestTimingMiddleware> _logger;
public RequestTimingMiddleware(RequestDelegate next, ILogger<RequestTimingMiddleware> logger)
{
_next = next;
_logger = logger;
}
public async Task InvokeAsync(HttpContext context)
{
var stopwatch = Stopwatch.StartNew();
await _next(context); // Call the next middleware
stopwatch.Stop();
_logger.LogInformation(
"Request {Method} {Path} completed in {Elapsed}ms",
context.Request.Method,
context.Request.Path,
stopwatch.ElapsedMilliseconds);
}
}
// Registration in Program.cs
app.UseMiddleware<RequestTimingMiddleware>();สิ่งที่ต้องทราบคือ class ของ middleware จะถูกสร้างครั้งเดียว (singleton lifetime) ในขณะที่ InvokeAsync จะถูกเรียกทุกครั้งที่มี request ความแตกต่างนี้มีความสำคัญต่อ thread safety
4. ความแตกต่างระหว่าง app.Use(), app.Run() และ app.Map() คืออะไร?
app.Use() เพิ่ม middleware ที่เรียก delegate ถัดไป app.Run() เป็น terminal middleware ที่ไม่เรียก next ซึ่งจะยุติ pipeline app.Map() แยกสาขา pipeline ตามเส้นทางของ request ข้อผิดพลาดที่พบบ่อยคือการวาง app.Run() เร็วเกินไป ซึ่งจะ short-circuit middleware ทั้งหมดที่อยู่ด้านล่าง
5. กลไก short-circuiting ของ middleware ทำงานอย่างไร?
Middleware ใดก็ได้สามารถ short-circuit pipeline โดยไม่เรียก next() นี่คือวิธีการทำงานของ UseStaticFiles(): ถ้าไฟล์สแตติกตรงกับเส้นทาง request มันจะส่งคืนไฟล์โดยตรงโดยไม่เรียก middleware authentication, authorization หรือ routing Middleware สำหรับ rate-limiting ก็ใช้ short-circuiting เพื่อส่งคืน response 429 ก่อนถึง endpoint
6. มีอะไรเปลี่ยนแปลงกับ middleware ใน .NET 9?
.NET 9 ขยายการรองรับ keyed dependency injection ไปยัง middleware แอตทริบิวต์ [FromKeyedServices] สามารถใช้ได้ทั้งใน constructor ของ middleware (สำหรับ service แบบ singleton/transient) และ method InvokeAsync (สำหรับทุก lifetime รวมถึง scoped) สิ่งนี้ช่วยขจัดความจำเป็นในการใช้ service locator workaround เมื่อ middleware ต้องการ implementation ที่แตกต่างกันของ interface เดียวกัน
คำถามเกี่ยวกับ Dependency Injection
7. Service lifetime ทั้งสามแบบของ DI คืออะไร?
ASP.NET Core มี lifetime สามแบบ: Transient (instance ใหม่ทุกครั้ง), Scoped (หนึ่ง instance ต่อ HTTP request) และ Singleton (หนึ่ง instance ตลอดอายุการใช้งานของแอปพลิเคชัน) การเลือก lifetime มีผลโดยตรงต่อการใช้หน่วยความจำ, thread safety และการแชร์ state ระหว่างส่วนประกอบต่าง ๆ
การ inject scoped service เข้าไปใน singleton จะสร้าง captive dependency: scoped service จะมีอายุยาวนานเท่ากับ singleton โดยแชร์ state ข้ามหลาย request เปิดใช้งาน ValidateScopes ในโหมด development เพื่อตรวจจับปัญหานี้ตั้งแต่ตอนเริ่มต้น
8. อธิบายปัญหา captive dependency พร้อมตัวอย่าง
เมื่อ singleton service รับ scoped dependency ผ่าน constructor, instance ของ scoped จะไม่ถูก dispose ระหว่าง request มันจะถูก "กักขัง" อยู่ใน lifetime ของ singleton สิ่งนี้ทำให้เกิดการแชร์ state ข้ามหลาย HTTP request ซึ่งอาจทำให้เกิดการรั่วไหลของข้อมูลและ race condition
builder.Services.AddScoped<IUserRepository, UserRepository>();
builder.Services.AddSingleton<ICacheService, CacheService>(); // CacheService takes IUserRepository
// This throws at startup in Development when ValidateScopes is enabled:
builder.Host.UseDefaultServiceProvider(options =>
{
options.ValidateScopes = true; // Catches captive dependencies
options.ValidateOnBuild = true; // Validates all registrations at startup
});วิธีแก้ไข: inject IServiceScopeFactory เข้าไปใน singleton และสร้าง scope ด้วยตนเองเมื่อต้องการ scoped service
9. Keyed services คืออะไร และควรใช้เมื่อไร?
Keyed services ที่เปิดตัวใน .NET 8 ช่วยให้สามารถลงทะเบียน implementation หลายตัวของ interface เดียวกันโดยใช้ key ที่แตกต่างกัน คุณสมบัตินี้ช่วยขจัด pattern factory แบบกำหนดเองและ logic การ resolve แบบมีเงื่อนไขที่ซับซ้อน
builder.Services.AddKeyedSingleton<INotificationService, EmailNotification>("email");
builder.Services.AddKeyedSingleton<INotificationService, SmsNotification>("sms");
builder.Services.AddKeyedSingleton<INotificationService, PushNotification>("push");
// Resolving in a controller or service
public class OrderService
{
public OrderService(
[FromKeyedServices("email")] INotificationService emailService,
[FromKeyedServices("sms")] INotificationService smsService)
{
// Each parameter gets its specific implementation
}
}ก่อนที่จะมี keyed services จำเป็นต้องใช้ factory class, named registration กับ third-party container หรือการ resolve ด้วยตนเองจาก IServiceProvider
10. ยังจำเป็นต้องใช้ third-party DI container กับ ASP.NET Core หรือไม่?
Built-in container ครอบคลุมสถานการณ์ส่วนใหญ่ตั้งแต่ .NET 9/10: constructor injection, keyed services, open generics และ decorator pattern (ผ่านการลงทะเบียนด้วยตนเอง) Third-party container เช่น Autofac หรือ Lamar ยังคงมีประโยชน์สำหรับสถานการณ์ขั้นสูง เช่น property injection, interception/AOP, การลงทะเบียนแบบ module หรือ convention-based scanning ในหลาย assembly สำหรับแอปพลิเคชันส่วนใหญ่ built-in container เพียงพอแล้ว
11. DI ทำงานอย่างไรใน minimal APIs เทียบกับ controllers?
Controllers รับ dependency ผ่าน constructor injection ส่วน endpoint ของ minimal API รับเป็น parameter ของ method ซึ่งถูก resolve โดยอัตโนมัติจาก DI container ประเภทพิเศษเช่น HttpContext, CancellationToken และ ClaimsPrincipal ก็ถูก auto-bind โดยไม่ต้องลงทะเบียนอย่างชัดเจน
12. Options pattern คืออะไร?
Options pattern ทำหน้าที่ผูก configuration section กับ class ที่เป็น strongly-typed ช่วยแยก configuration ออกจาก logic ของ service และรองรับ validation, named options และ runtime reload ผ่าน IOptionsMonitor<T> การ inject raw IConfiguration เข้าไปใน service ถือเป็น anti-pattern เพราะจะทำให้ service ผูกติดกับโครงสร้างของ configuration
พร้อมที่จะพิชิตการสัมภาษณ์ .NET แล้วหรือยังครับ?
ฝึกฝนด้วยตัวจำลองแบบโต้ตอบ, flashcards และแบบทดสอบเทคนิคครับ
คำถามเกี่ยวกับ Minimal APIs
13. Minimal APIs คืออะไร และแตกต่างจาก controllers อย่างไร?
Minimal APIs ที่เปิดตัวใน .NET 6 กำหนด HTTP endpoint โดยตรงใน Program.cs โดยใช้ app.MapGet(), app.MapPost() และ method ที่คล้ายกัน ช่วยขจัดความจำเป็นในการใช้ controller class, model binding attribute และ action filter ในขณะที่ controllers มีการรองรับ filter, model validation และ content negotiation ในตัว Minimal APIs มีความกระชับกว่าแต่ต้องตั้งค่า cross-cutting concern ด้วยตนเอง
14. ควรเลือก minimal APIs แทน controllers เมื่อไร?
Minimal APIs เหมาะกับ microservice, API แบบ lightweight และสถานการณ์ที่ประสิทธิภาพการเริ่มต้นมีความสำคัญ Controllers เหมาะกับแอปพลิเคชันขนาดใหญ่ที่มี filtering pipeline ที่ซับซ้อน, model binding ที่ครอบคลุม หรือทีมที่คุ้นเคยกับ convention ของ MVC ทั้งสองสามารถอยู่ร่วมกันในแอปพลิเคชันเดียวกัน
15. วิธีจัดโครงสร้าง minimal APIs ในโปรเจกต์จริง?
หลีกเลี่ยงการวาง endpoint ทั้งหมดใน Program.cs ควรใช้ extension method เพื่อจัดระเบียบ endpoint ตามฟีเจอร์หรือ domain โดยรักษา route handler ให้บางเบาและมอบหมาย business logic ให้กับ service
public static class ProductEndpoints
{
public static void MapProductEndpoints(this WebApplication app)
{
var group = app.MapGroup("/api/products")
.WithTags("Products")
.RequireAuthorization();
group.MapGet("/", GetAll);
group.MapGet("/{id:int}", GetById);
group.MapPost("/", Create);
}
private static async Task<IResult> GetAll(
IProductService productService, // Auto-resolved from DI
CancellationToken cancellationToken)
{
var products = await productService.GetAllAsync(cancellationToken);
return TypedResults.Ok(products);
}
private static async Task<IResult> GetById(
int id,
IProductService productService)
{
var product = await productService.GetByIdAsync(id);
return product is null
? TypedResults.NotFound()
: TypedResults.Ok(product);
}
private static async Task<IResult> Create(
CreateProductRequest request,
IProductService productService)
{
var product = await productService.CreateAsync(request);
return TypedResults.Created($"/api/products/{product.Id}", product);
}
}
// Program.cs — Clean registration
app.MapProductEndpoints();รูปแบบนี้สามารถ scale ได้ดี: แต่ละโฟลเดอร์ฟีเจอร์จะประกอบด้วย endpoint, DTO และ service interface ของตัวเอง
16. Validation ทำงานอย่างไรใน minimal APIs?
.NET 10 เปิดตัว validation ในตัวสำหรับ minimal APIs ก่อน .NET 10 การ validate ต้องทำด้วยตนเองหรือใช้ library ภายนอกอย่าง FluentValidation ใน .NET 10 data annotations บน parameter type จะถูก validate โดยอัตโนมัติ และ request ที่ไม่ถูกต้องจะส่งคืน response 400 พร้อม problem details
17. TypedResults คืออะไร และทำไมถึงควรใช้?
TypedResults (เปิดตัวใน .NET 7) ให้ type safety ในเวลา compile สำหรับ API response และช่วยให้สร้างเอกสาร OpenAPI ได้โดยอัตโนมัติ ต่างจาก Results ที่คืน IResult, method ของ TypedResults จะคืนประเภทเฉพาะเช่น Ok<T> หรือ NotFound ช่วยให้ framework สร้าง response schema ที่แม่นยำ
18. วิธีจัดการ Server-Sent Events ใน minimal APIs?
.NET 10 เพิ่ม TypedResults.ServerSentEvents() สำหรับ streaming response คุณสมบัตินี้ช่วยขจัดการเขียน Response.Body ด้วยตนเอง และจัดการ JSON serialization, header content-type และการจัดการ connection โดยอัตโนมัติ
คำถามขั้นสูง
19. Request pipeline โต้ตอบกับ endpoint routing อย่างไร?
UseRouting() จับคู่ request ที่เข้ามากับ endpoint แต่ไม่ได้ execute มัน Middleware ที่อยู่ระหว่าง UseRouting() กับ MapControllers()/MapEndpoints() สามารถตรวจสอบ metadata ของ endpoint ที่ตรงกัน (เช่น authorization attribute) ก่อนการ execute นี่คือวิธีที่ UseAuthorization() อ่าน attribute [Authorize] ที่กำหนดบน controller หรือ endpoint ของ minimal API
20. ความแตกต่างระหว่าง AddTransient, AddScoped และ AddSingleton สำหรับ IHttpClientFactory คืออะไร?
ไม่ควรลงทะเบียน HttpClient เป็น singleton เนื่องจากจะไม่สนใจการเปลี่ยนแปลง DNS และทำให้ socket connection หมด IHttpClientFactory (ผ่าน AddHttpClient()) จัดการ lifetime ของ HttpClient อย่างถูกต้อง: instance ของ HttpClient เป็น transient แต่ pool ของ HttpMessageHandler ที่อยู่เบื้องล่างจะถูกจัดการด้วย lifetime ที่กำหนดได้ (ค่าเริ่มต้น 2 นาที) สิ่งนี้ป้องกัน socket exhaustion ขณะเดียวกันก็เคารพ DNS TTL
21. วิธีนำ decorator pattern มาใช้กับ built-in DI?
Built-in container ไม่มีการรองรับ decorator โดยตรง แต่สามารถทำได้ด้วยตนเองโดยใช้ factory delegate
// Decorating IProductService with caching
builder.Services.AddScoped<ProductService>();
builder.Services.AddScoped<IProductService>(sp =>
{
var inner = sp.GetRequiredService<ProductService>();
var cache = sp.GetRequiredService<IMemoryCache>();
return new CachedProductService(inner, cache);
});สำหรับแอปพลิเคชันที่ต้องการ decorator จำนวนมาก third-party container อย่าง Scrutor มี API Decorate<TInterface, TDecorator>() ที่สะอาดกว่า
22. Middleware แตกต่างจาก endpoint filter ใน minimal APIs อย่างไร?
Middleware ทำงานกับทุก request ใน pipeline ไม่ว่า endpoint จะเป็นอะไร Endpoint filter (เปิดตัวใน .NET 7) ทำงานเฉพาะกับ endpoint ที่ตรงกัน คล้ายกับ action filter ใน MVC Filter สามารถเข้าถึง context เฉพาะของ endpoint และลงทะเบียนต่อ route หรือต่อ group ใช้ middleware สำหรับ cross-cutting concern เช่น logging และ CORS ใช้ filter สำหรับ logic เฉพาะ endpoint เช่น validation หรือ transformation
23. HybridCache ใน .NET 9 คืออะไร?
HybridCache รวม caching แบบ in-memory (L1) และ distributed (L2) ไว้ภายใต้ API เดียว มันจัดการการป้องกัน cache stampede โดยอัตโนมัติ: เมื่อหลาย request พร้อมกันพลาด cache สำหรับ key เดียวกัน มีเพียง request เดียวที่จะ execute factory method ในขณะที่ request อื่นรอ สิ่งนี้มาแทนที่การประสานงานด้วยตนเองระหว่าง IMemoryCache + IDistributedCache ที่มักเกิดข้อผิดพลาด
24. วิธีทดสอบ middleware แบบแยกส่วน?
Middleware สามารถทดสอบได้โดยใช้ DefaultHttpContext และ RequestDelegate แบบกำหนดเอง สร้าง instance ของ middleware ส่ง mock context และ assert บน property ของ response
[Fact]
public async Task Middleware_LogsElapsedTime()
{
var logger = new FakeLogger<RequestTimingMiddleware>();
var middleware = new RequestTimingMiddleware(
next: (ctx) => Task.CompletedTask, // Terminal delegate
logger: logger);
var context = new DefaultHttpContext();
context.Request.Method = "GET";
context.Request.Path = "/api/products";
await middleware.InvokeAsync(context);
Assert.Single(logger.LogEntries);
Assert.Contains("completed in", logger.LogEntries[0].Message);
}สำหรับ integration test WebApplicationFactory<T> ให้การทดสอบ pipeline แบบเต็มรวมถึงลำดับ middleware
25. การเปลี่ยนแปลง OpenAPI ใน .NET 9 และ .NET 10 มีอะไรบ้าง?
.NET 9 แทนที่ Swagger/Swashbuckle ด้วยการสร้างเอกสาร OpenAPI ในตัวผ่าน Microsoft.AspNetCore.OpenApi ส่วน .NET 10 อัปเกรดเป็น OpenAPI library v2.0 พร้อมรองรับ YAML, schema ประเภท nullable ที่ดีขึ้น (ใช้ oneOf แทน property nullable) และการรวมคอมเมนต์เอกสาร XML ที่ดีขึ้น เอกสารที่สร้างจะถูกให้บริการที่ /openapi/v1.json เป็นค่าเริ่มต้น
ฝึกอธิบาย middleware pipeline บนไวท์บอร์ด: วาด request ที่ไหลลงผ่าน middleware แต่ละตัวและ response ที่ไหลกลับขึ้น ผู้สัมภาษณ์ที่บริษัทเช่น Microsoft, Accenture และบริษัทที่ปรึกษามักใช้แบบฝึกหัดนี้เพื่อประเมินความลึกซึ้งของความเข้าใจ
สรุป
- ลำดับการทำงานของ middleware เป็นแบบ deterministic และมีความสำคัญต่อความปลอดภัย: exception handling ก่อน, static files ก่อน auth, routing ก่อน authorization
- ปัญหา captive dependency (scoped อยู่ใน singleton) เป็นบั๊ก DI ที่พบบ่อยที่สุด ควรเปิดใช้
ValidateScopesและValidateOnBuildในโหมด development - Keyed services ใน .NET 8/9 ช่วยขจัดความจำเป็นส่วนใหญ่ในการใช้ third-party DI container หรือ pattern factory แบบกำหนดเอง
- Minimal APIs และ controllers สามารถอยู่ร่วมกันได้ ควรเลือกตามความซับซ้อนของโปรเจกต์ convention ของทีม และความต้องการ filtering
- จัดโครงสร้าง minimal APIs โดยใช้ extension method และ route group เพื่อรักษา
Program.csให้สะอาด - .NET 10 เพิ่ม validation ในตัวสำหรับ minimal API, รองรับ SSE ผ่าน TypedResults และปรับปรุงการสร้าง OpenAPI
- ทดสอบ middleware แบบแยกส่วนด้วย
DefaultHttpContextใช้WebApplicationFactoryสำหรับ integration test
ฝึกฝนคำถามเหล่านี้ด้วยโค้ดจริงบน ตัวจำลองสัมภาษณ์ .NET ของ SharpSkill ซึ่งครอบคลุมโมดูล minimal APIs, การพัฒนา Web API และ clean architecture
เริ่มฝึกซ้อมเลย!
ทดสอบความรู้ของคุณด้วยตัวจำลองสัมภาษณ์และแบบทดสอบเทคนิคครับ
แท็ก
แชร์
บทความที่เกี่ยวข้อง

.NET MAUI ในปี 2026: การพัฒนา Cross-Platform และคำถามสัมภาษณ์งาน
บทความสอน .NET MAUI ครอบคลุมการพัฒนา cross-platform ด้วย .NET 10, handler architecture, MVVM, HybridWebView และคำถามสัมภาษณ์งานที่สำคัญในปี 2026

คำถามสัมภาษณ์ C# และ .NET: คู่มือฉบับสมบูรณ์ 2026
คำถามสัมภาษณ์ C# และ .NET ที่พบบ่อยที่สุด 17 ข้อ LINQ, async/await, dependency injection, Entity Framework และ best practice พร้อมคำตอบละเอียดและตัวอย่างโค้ด

Entity Framework Core: การเพิ่มประสิทธิภาพและแนวทางปฏิบัติที่ดีที่สุดในปี 2026
คู่มือฉบับสมบูรณ์สำหรับการเพิ่มประสิทธิภาพ Entity Framework Core 10 บน .NET 10 เรียนรู้ AsNoTracking, compiled queries, batch updates, split queries และตัวดำเนินการ LeftJoin