Top 25 Câu Hỏi Phỏng Vấn ASP.NET Core: Middleware, DI và Minimal APIs
Tổng hợp 25 câu hỏi phỏng vấn ASP.NET Core về middleware pipeline, dependency injection, minimal APIs kèm giải đáp chi tiết và ví dụ code thực tế.

Câu hỏi phỏng vấn ASP.NET Core về middleware, dependency injection và minimal APIs luôn nằm trong nhóm chủ đề thường gặp nhất tại các buổi phỏng vấn kỹ thuật .NET. Dù vị trí ứng tuyển hướng đến backend hay full-stack .NET, nhà tuyển dụng thường xuyên đánh giá mức độ hiểu biết về request pipeline, service lifetime và mô hình API nhẹ được giới thiệu từ .NET 6 và tinh chỉnh qua .NET 10.
Thứ tự middleware pipeline, lỗi lifetime không khớp trong DI (vấn đề captive dependency), và khả năng phân tích trade-off giữa minimal APIs và controllers. Ba lĩnh vực này chiếm phần lớn câu hỏi phỏng vấn ASP.NET Core ở cấp độ mid-to-senior.
Câu Hỏi Về Middleware Pipeline ASP.NET Core
1. Middleware trong ASP.NET Core là gì?
Middleware là thành phần được lắp ráp vào pipeline ứng dụng để xử lý request và response. Mỗi middleware chọn chuyển tiếp request đến thành phần tiếp theo hoặc short-circuit pipeline. Middleware thực thi theo thứ tự đăng ký trong Program.cs, và response đi ngược lại qua cùng các thành phần theo thứ tự đảo ngược.
2. Thứ tự thực thi middleware hoạt động như thế nào?
Thứ tự các lệnh gọi app.Use*() trong Program.cs xác định trình tự thực thi chính xác. Request chảy từ trên xuống qua mỗi middleware, và response chảy từ dưới lên. Đó là lý do UseAuthentication() phải xuất hiện trước UseAuthorization(), và UseRouting() trước 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();Đặt UseStaticFiles() trước authentication giúp tránh kiểm tra auth không cần thiết trên các request CSS, JS và hình ảnh. Đây là câu hỏi follow-up phổ biến trong phỏng vấn.
3. Cách viết custom middleware như thế nào?
Custom middleware có thể triển khai dưới dạng class với method InvokeAsync hoặc inline bằng app.Use(). Cách tiếp cận dạng class được ưu tiên cho code production vì hỗ trợ dependency injection thông qua tham số 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>();Cần lưu ý rằng class middleware được khởi tạo một lần (singleton lifetime) trong khi InvokeAsync được gọi theo từng request. Sự khác biệt này quan trọng đối với thread safety.
4. Sự khác biệt giữa app.Use(), app.Run() và app.Map() là gì?
app.Use() thêm middleware gọi delegate tiếp theo. app.Run() là terminal middleware không gọi next, kết thúc pipeline. app.Map() phân nhánh pipeline dựa trên đường dẫn request. Một lỗi phổ biến là đặt app.Run() quá sớm, dẫn đến short-circuit toàn bộ middleware phía sau.
5. Cơ chế short-circuiting của middleware hoạt động ra sao?
Bất kỳ middleware nào cũng có thể short-circuit pipeline bằng cách không gọi next(). Đây là cách UseStaticFiles() hoạt động: nếu file tĩnh khớp với đường dẫn request, nó trả về file trực tiếp mà không gọi middleware authentication, authorization hay routing. Middleware rate-limiting cũng sử dụng short-circuiting để trả về response 429 trước khi đến endpoint.
6. Có gì thay đổi với middleware trong .NET 9?
.NET 9 mở rộng hỗ trợ keyed dependency injection cho middleware. Attribute [FromKeyedServices] giờ hoạt động trong cả constructor middleware (cho service singleton/transient) và method InvokeAsync (cho tất cả lifetime bao gồm scoped). Điều này loại bỏ nhu cầu sử dụng workaround service locator khi middleware cần các implementation khác nhau của cùng một interface.
Câu Hỏi Về Dependency Injection
7. Ba service lifetime trong DI là gì?
ASP.NET Core cung cấp ba lifetime: Transient (instance mới mỗi lần), Scoped (một instance mỗi HTTP request), và Singleton (một instance cho toàn bộ vòng đời ứng dụng). Lựa chọn này ảnh hưởng trực tiếp đến việc sử dụng bộ nhớ, thread safety và chia sẻ state giữa các thành phần.
Inject scoped service vào singleton tạo ra captive dependency: scoped service tồn tại lâu bằng singleton, chia sẻ state giữa các request. Bật ValidateScopes trong development để phát hiện lỗi này khi khởi động.
8. Giải thích vấn đề captive dependency bằng ví dụ
Khi singleton service nhận scoped dependency thông qua constructor, instance scoped đó không bao giờ được dispose giữa các request. Nó trở thành "captive" trong vòng đời của singleton. Điều này dẫn đến chia sẻ state giữa các HTTP request, có thể gây rò rỉ dữ liệu và 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
});Cách khắc phục: inject IServiceScopeFactory vào singleton và tạo scope thủ công khi cần scoped service.
9. Keyed services là gì và khi nào nên sử dụng?
Keyed services, ra mắt trong .NET 8, cho phép đăng ký nhiều implementation của cùng interface với các key khác nhau. Tính năng này loại bỏ các pattern factory tùy chỉnh và logic phân giải có điều kiện phức tạp.
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
}
}Trước keyed services, việc này yêu cầu class factory, named registration với third-party container, hoặc phân giải thủ công từ IServiceProvider.
10. Third-party DI container có còn cần thiết với ASP.NET Core không?
Built-in container đáp ứng hầu hết các tình huống kể từ .NET 9/10: constructor injection, keyed services, open generics và decorator pattern (thông qua đăng ký thủ công). Third-party container như Autofac hoặc Lamar vẫn hữu ích cho các tình huống nâng cao như property injection, interception/AOP, đăng ký dựa trên module, hoặc convention-based scanning trên toàn assembly lớn. Đối với hầu hết ứng dụng, built-in container là đủ.
11. DI hoạt động khác nhau thế nào giữa minimal APIs và controllers?
Controllers nhận dependency thông qua constructor injection. Endpoint minimal API nhận chúng dưới dạng tham số method, được resolve tự động từ DI container. Các kiểu đặc biệt như HttpContext, CancellationToken và ClaimsPrincipal cũng được auto-bind mà không cần đăng ký rõ ràng.
12. Options pattern là gì?
Options pattern liên kết các section cấu hình với class strongly-typed. Nó tách biệt cấu hình khỏi logic service và hỗ trợ validation, named options, và reload runtime thông qua IOptionsMonitor<T>. Inject raw IConfiguration vào service là anti-pattern vì nó gắn chặt service với cấu trúc cấu hình.
Sẵn sàng chinh phục phỏng vấn .NET?
Luyện tập với mô phỏng tương tác, flashcards và bài kiểm tra kỹ thuật.
Câu Hỏi Về Minimal APIs
13. Minimal APIs là gì và khác gì so với controllers?
Minimal APIs, ra mắt trong .NET 6, định nghĩa HTTP endpoint trực tiếp trong Program.cs bằng app.MapGet(), app.MapPost() và các method tương tự. Chúng loại bỏ nhu cầu class controller, attribute model binding và action filter. Controllers cung cấp hỗ trợ tích hợp cho filter, model validation và content negotiation. Minimal APIs gọn nhẹ hơn nhưng cần thiết lập thủ công cho cross-cutting concern.
14. Khi nào nên chọn minimal APIs thay vì controllers?
Minimal APIs phù hợp với microservice, API nhẹ và các tình huống mà hiệu suất khởi động quan trọng. Controllers phù hợp với ứng dụng lớn có pipeline filtering phức tạp, model binding mở rộng hoặc team quen với convention MVC. Cả hai có thể cùng tồn tại trong một ứng dụng.
15. Cách tổ chức minimal APIs trong dự án thực tế?
Tránh đặt tất cả endpoint trong Program.cs. Sử dụng extension method để tổ chức endpoint theo tính năng hoặc domain, giữ route handler mỏng và ủy thác logic nghiệp vụ cho 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();Mô hình này mở rộng tốt: mỗi thư mục tính năng chứa endpoint, DTO và interface service của nó.
16. Validation hoạt động thế nào trong minimal APIs?
.NET 10 giới thiệu validation tích hợp cho minimal APIs. Trước .NET 10, validation yêu cầu triển khai thủ công hoặc thư viện bên thứ ba như FluentValidation. Với .NET 10, data annotations trên kiểu tham số được validate tự động, và request không hợp lệ trả về response 400 kèm problem details.
17. TypedResults là gì và tại sao nên sử dụng?
TypedResults (ra mắt trong .NET 7) cung cấp type safety tại thời điểm biên dịch cho response API và cho phép tạo tài liệu OpenAPI tự động. Khác với Results trả về IResult, các method TypedResults trả về kiểu cụ thể như Ok<T> hoặc NotFound, cho phép framework tạo schema response chính xác.
18. Cách xử lý Server-Sent Events trong minimal APIs?
.NET 10 thêm TypedResults.ServerSentEvents() cho streaming response. Tính năng này loại bỏ việc viết thủ công Response.Body và xử lý JSON serialization, header content-type và quản lý kết nối tự động.
Câu Hỏi Nâng Cao
19. Request pipeline tương tác với endpoint routing như thế nào?
UseRouting() khớp request đến với endpoint nhưng không thực thi nó. Middleware giữa UseRouting() và MapControllers()/MapEndpoints() có thể kiểm tra metadata endpoint đã khớp (ví dụ: attribute authorization) trước khi thực thi. Đây là cách UseAuthorization() đọc attribute [Authorize] được đặt trên controller hoặc endpoint minimal API.
20. Sự khác biệt giữa AddTransient, AddScoped và AddSingleton cho IHttpClientFactory?
Không bao giờ đăng ký HttpClient dưới dạng singleton: nó bỏ qua thay đổi DNS và cạn kiệt kết nối socket. IHttpClientFactory (qua AddHttpClient()) quản lý lifetime HttpClient đúng cách: các instance HttpClient là transient, nhưng pool HttpMessageHandler bên dưới được quản lý với lifetime có thể cấu hình (mặc định 2 phút). Điều này ngăn cạn kiệt socket đồng thời tôn trọng TTL DNS.
21. Cách triển khai decorator pattern với built-in DI?
Built-in container không có hỗ trợ decorator gốc, nhưng có thể thực hiện thủ công bằng 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);
});Đối với ứng dụng cần nhiều decorator, third-party container như Scrutor cung cấp API Decorate<TInterface, TDecorator>() gọn gàng hơn.
22. Middleware khác gì so với endpoint filter trong minimal APIs?
Middleware chạy cho mọi request trong pipeline, bất kể endpoint. Endpoint filter (ra mắt trong .NET 7) chỉ chạy cho endpoint đã khớp, tương tự action filter trong MVC. Filter có quyền truy cập vào context cụ thể của endpoint và được đăng ký per-route hoặc per-group. Sử dụng middleware cho cross-cutting concern như logging và CORS; sử dụng filter cho logic cụ thể endpoint như validation hoặc transformation.
23. HybridCache trong .NET 9 là gì?
HybridCache kết hợp caching in-memory (L1) và distributed (L2) sau một API duy nhất. Nó tự động xử lý bảo vệ cache stampede: khi nhiều request đồng thời miss cache cho cùng key, chỉ một request thực thi factory method trong khi các request khác chờ. Điều này thay thế việc phối hợp thủ công IMemoryCache + IDistributedCache vốn dễ phát sinh lỗi trước đó.
24. Cách test middleware riêng biệt?
Middleware có thể được test bằng DefaultHttpContext và RequestDelegate tùy chỉnh. Tạo instance của middleware, truyền mock context và assert trên các thuộc tính 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);
}Đối với integration test, WebApplicationFactory<T> cung cấp kiểm thử pipeline đầy đủ bao gồm thứ tự middleware.
25. Những thay đổi OpenAPI trong .NET 9 và .NET 10?
.NET 9 thay thế Swagger/Swashbuckle bằng tạo tài liệu OpenAPI tích hợp qua Microsoft.AspNetCore.OpenApi. .NET 10 nâng cấp lên thư viện OpenAPI v2.0 với hỗ trợ YAML, schema kiểu nullable tốt hơn (sử dụng oneOf thay vì thuộc tính nullable), và tích hợp comment tài liệu XML tốt hơn. Tài liệu được phục vụ tại /openapi/v1.json theo mặc định.
Thực hành giải thích middleware pipeline trên bảng trắng: vẽ request chảy xuống qua mỗi middleware và response chảy ngược lên. Nhà tuyển dụng tại các công ty như Microsoft, Accenture và các công ty tư vấn thường sử dụng bài tập này để đánh giá mức độ hiểu biết.
Kết Luận
- Thứ tự thực thi middleware mang tính xác định và quan trọng về bảo mật: exception handling trước, static files trước auth, routing trước authorization
- Vấn đề captive dependency (scoped bên trong singleton) là bug DI phổ biến nhất; bật
ValidateScopesvàValidateOnBuildtrong development - Keyed services trong .NET 8/9 loại bỏ hầu hết nhu cầu sử dụng third-party DI container hoặc pattern factory tùy chỉnh
- Minimal APIs và controllers cùng tồn tại; chọn dựa trên độ phức tạp dự án, convention của team và yêu cầu filtering
- Tổ chức minimal APIs bằng extension method và route group để giữ
Program.csgọn gàng - .NET 10 thêm validation tích hợp cho minimal API, hỗ trợ SSE qua TypedResults, và cải thiện tạo OpenAPI
- Test middleware riêng biệt với
DefaultHttpContext; sử dụngWebApplicationFactorycho integration test
Thực hành các câu hỏi này với code thực trên trình giả lập phỏng vấn .NET của SharpSkill bao gồm các module minimal APIs, phát triển Web API, và clean architecture.
Bắt đầu luyện tập!
Kiểm tra kiến thức với mô phỏng phỏng vấn và bài kiểm tra kỹ thuật.
Thẻ
Chia sẻ
Bài viết liên quan

.NET MAUI trong 2026: Phát triển Cross-Platform và Câu hỏi Phỏng vấn
Hướng dẫn .NET MAUI toàn diện về phát triển cross-platform với .NET 10, handler architecture, MVVM, HybridWebView và các câu hỏi phỏng vấn quan trọng năm 2026.

Câu Hỏi Phỏng Vấn C# và .NET: Hướng Dẫn Đầy Đủ 2026
17 câu hỏi phỏng vấn C# và .NET thường gặp nhất. LINQ, async/await, dependency injection, Entity Framework và các phương pháp tốt nhất với đáp án chi tiết.

Entity Framework Core: Tối Ưu Hiệu Năng và Các Phương Pháp Tốt Nhất Năm 2026
Hướng dẫn toàn diện về tối ưu hiệu năng Entity Framework Core 10 trên .NET 10. Tìm hiểu AsNoTracking, compiled queries, batch updates, split queries và toán tử LeftJoin.