Ngân hàng câu hỏi ASP.NET Core và EF Core
A. .NET / .NET Core / .NET Framework
1. .NET, .NET Core, .NET Framework — khác gì?
- .NET Framework: bản gốc 2002, chỉ Windows, đã không có version mới (cuối cùng 4.8).
- .NET Core: cross-platform, mã nguồn mở, hiệu năng cao (3.1 LTS, 2020).
- .NET 5+: thống nhất, gọi là ".NET" (5, 6, 7, 8, 9, 10…). Bản chất là .NET Core.
LTS hiện nay: .NET 8 (Nov 2023), .NET 10 (Nov 2025).
2. CLR là gì?
Common Language Runtime — virtual machine của .NET. Chịu trách nhiệm:
- JIT compile IL → machine code.
- Garbage Collection.
- Type safety, exception handling.
- Security.
3. IL (Intermediate Language) / Managed Code?
- Code C# → compiler tạo IL (bytecode).
- IL nằm trong file .dll / .exe.
- Runtime CLR JIT-compile IL → native machine code.
- Code chạy qua CLR gọi là managed.
4. CTS, CLS là gì?
- CTS (Common Type System): tập kiểu chung mọi ngôn ngữ .NET dùng.
- CLS (Common Language Specification): subset của CTS bảo đảm interop giữa các ngôn ngữ.
5. NuGet là gì?
Package manager cho .NET — install/restore library. dotnet add package <name> hoặc Visual Studio Package Manager.
B. ASP.NET Core cơ bản
6. ASP.NET Core có gì khác ASP.NET (cũ)?
- Cross-platform (Windows, Linux, macOS).
- Self-hosted (Kestrel), không cần IIS.
- DI built-in.
- Middleware pipeline thay vì HTTP Module/Handler.
- Cấu hình bằng JSON/env, không web.config.
- Modular qua NuGet.
7. Kestrel là gì?
Web server cross-platform built-in của ASP.NET Core. Có thể chạy trực tiếp (production-grade) hoặc đứng sau reverse proxy (Nginx, IIS).
8. Cấu trúc Program.cs (.NET 8/9)?
var builder = WebApplication.CreateBuilder(args);
// Đăng ký service (DI)
builder.Services.AddControllers();
var app = builder.Build();
// Middleware pipeline
app.UseAuthentication();
app.UseAuthorization();
app.MapControllers();
app.Run();
.NET 6+ dùng minimal hosting — không cần Startup.cs.
9. appsettings.json hoạt động ra sao?
File config JSON, được load theo thứ tự:
appsettings.jsonappsettings.{Environment}.json(Development/Production)- User secrets (Dev)
- Environment variables
- Command-line args
Mỗi nguồn ghi đè nguồn trước. Truy cập qua IConfiguration hoặc IOptions<T>.
10. Sự khác giữa IOptions<T>, IOptionsSnapshot<T>, IOptionsMonitor<T>?
IOptions<T>: load 1 lần khi register, không refresh.IOptionsSnapshot<T>: refresh mỗi request (Scoped).IOptionsMonitor<T>: refresh real-time + có event change.
C. Middleware
11. Middleware là gì?
Component xử lý HTTP request trong pipeline. Có thể inspect, modify, short-circuit (không gọi next).
12. Thứ tự middleware quan trọng ra sao?
Cực kỳ. Pipeline order:
UseExceptionHandler / DeveloperExceptionPage
UseHttpsRedirection
UseStaticFiles
UseRouting
UseCors
UseAuthentication
UseAuthorization
UseEndpoints / MapControllers
13. app.Use vs app.Run vs app.Map?
Use: middleware cónext— chuyển control xuống.Run: terminal middleware, không gọi tiếp.Map: branch pipeline theo path.
14. Viết custom middleware?
public class TimingMiddleware {
private readonly RequestDelegate _next;
public TimingMiddleware(RequestDelegate next) => _next = next;
public async Task InvokeAsync(HttpContext ctx) {
var sw = Stopwatch.StartNew();
await _next(ctx);
Console.WriteLine($"{ctx.Request.Path} took {sw.ElapsedMilliseconds}ms");
}
}
// Đăng ký:
app.UseMiddleware<TimingMiddleware>();
15. Global Exception Handler thực hiện sao?
Middleware bao try-catch ở đầu pipeline → trả JSON 500 nếu lỗi:
app.UseExceptionHandler(builder => builder.Run(async ctx => {
ctx.Response.StatusCode = 500;
var ex = ctx.Features.Get<IExceptionHandlerFeature>()?.Error;
await ctx.Response.WriteAsJsonAsync(new { error = ex?.Message });
}));
D. Dependency Injection
16. DI lifetimes — Singleton, Scoped, Transient?
- Singleton: 1 instance suốt app lifetime.
- Scoped: 1 instance / HTTP request.
- Transient: instance mới mỗi lần inject.
17. DbContext đăng ký lifetime gì? Vì sao?
Scoped. Vì:
DbContextkhông thread-safe.- Cần 1 instance / request để Unit of Work hoạt động đúng.
- Phải dispose cuối request.
18. Captive dependency là gì?
Inject Scoped (hoặc Transient) vào Singleton → Singleton ôm cố định Scoped đầu tiên, không bao giờ tạo mới. Memory leak + bug logic.
Fix: dùng IServiceScopeFactory để tự tạo scope khi cần.
19. Constructor injection vs Method injection vs Property injection?
- Constructor: chuẩn nhất — dependency bắt buộc, immutable.
- Method: dependency theo lần gọi (
[FromServices]trong controller method). - Property: dependency optional. Ít dùng.
20. AddTransient vs AddScoped vs AddSingleton — ví dụ?
services.AddSingleton<ICache, MemoryCache>(); // toàn app
services.AddScoped<IUserService, UserService>(); // mỗi request
services.AddTransient<IEmailFormatter, Formatter>(); // mỗi lần
21. Đăng ký nhiều implementation cho 1 interface?
services.AddScoped<INotifier, EmailNotifier>();
services.AddScoped<INotifier, SmsNotifier>();
// Inject IEnumerable<INotifier> → nhận hết
E. REST API
22. REST là gì? 6 ràng buộc?
Representational State Transfer:
- Client-Server
- Stateless
- Cacheable
- Uniform Interface
- Layered System
- Code on Demand (optional)
23. HTTP method nào idempotent?
- ✅ GET, PUT, DELETE, HEAD, OPTIONS.
- ❌ POST.
- PATCH không bắt buộc — design tốt thường idempotent.
24. POST vs PUT — khác gì?
- POST: tạo mới, không idempotent, server quyết URI (
/users→ tạo/users/123). - PUT: thay thế toàn bộ, idempotent, client biết URI (
PUT /users/123thay luôn).
25. PATCH khác PUT?
- PUT: gửi đầy đủ resource, thay thế.
- PATCH: gửi phần thay đổi (delta). Có thể dùng JSON Patch / JSON Merge Patch.
26. Trả status code nào khi tạo mới thành công?
201 Created + Location header trỏ tới URI mới + body resource vừa tạo:
return CreatedAtAction(nameof(Get), new { id = u.Id }, u);
27. 401 vs 403?
- 401 Unauthorized: chưa auth / token sai / hết hạn.
- 403 Forbidden: đã auth nhưng không có quyền cho action này.
28. CORS là gì? Bật ra sao?
Cross-Origin Resource Sharing — browser policy cho phép request cross-domain.
builder.Services.AddCors(o => o.AddPolicy("default",
p => p.WithOrigins("https://app.com")
.AllowAnyHeader().AllowAnyMethod()));
app.UseCors("default");
29. Versioning API — cách phổ biến?
- URI:
/api/v1/users,/api/v2/users(đơn giản, phổ biến nhất). - Header:
Api-Version: 2. - Query:
?version=2. - Media type:
Accept: application/vnd.app.v2+json.
Package: Asp.Versioning.Http.
30. Model binding & validation?
ASP.NET Core tự bind body/query/route vào DTO. Validation qua data annotation:
public class CreateUserDto {
[Required] public string Name { get; set; } = "";
[EmailAddress] public string Email { get; set; } = "";
[Range(18, 120)] public int Age { get; set; }
}
[ApiController] tự trả 400 nếu validation fail.
F. JWT Authentication
31. JWT là gì? Cấu trúc?
JSON Web Token — chuỗi header.payload.signature (base64url-encoded).
- Header: alg, typ.
- Payload: claims (sub, exp, role…).
- Signature: HMAC/RSA của header+payload.
32. JWT lưu ở đâu phía client?
- localStorage: dễ XSS đánh cắp.
- HttpOnly cookie: an toàn hơn nhưng cần CSRF protection.
- Memory + refresh token cookie: pattern hiện đại.
33. Authentication vs Authorization?
- Authentication: bạn là ai? (đăng nhập, verify identity).
- Authorization: bạn được làm gì? (role, policy, claim).
UseAuthentication luôn phải đặt trước UseAuthorization.
34. [Authorize(Roles = "Admin")] vs Policy?
- Role: cơ chế cũ, đơn giản.
- Policy: flexible, custom requirement (claim, role, dynamic).
services.AddAuthorization(o => o.AddPolicy("MinAge", p =>
p.RequireClaim("age", "18", "19", "20")));
[Authorize(Policy = "MinAge")]
35. Refresh token — vì sao cần?
JWT thường có expiry ngắn (15p–1h). Refresh token (lưu DB, expiry dài) đổi lấy JWT mới mà không cần đăng nhập lại. Revoke được khi user logout.
G. EF Core
36. EF Core khác EF6?
- EF Core: cross-platform, .NET Core/.NET 5+.
- Lightweight, hiệu năng tốt hơn.
- Hỗ trợ provider mới: SQL Server, PostgreSQL, MySQL, SQLite, In-Memory.
- Một số tính năng EF6 đã có: Lazy loading (qua proxy), TPT, Stored Procedure mapping — EF Core dần thêm lại qua version.
37. DbContext đại diện gì?
Unit of Work + Repository facade. Track entity changes, expose DbSet<T> query, commit qua SaveChanges().
38. Code-First vs Database-First?
- Code-First: viết entity C# trước, sinh DB qua migration. Mặc định EF Core.
- Database-First: DB đã có → scaffold ra entity (
dotnet ef dbcontext scaffold).
39. Lazy / Eager / Explicit loading?
- Lazy: load khi truy cập property (cần
UseLazyLoadingProxies+virtualnavigation). - Eager: dùng
Include, JOIN 1 lượt. - Explicit: gọi
Entry(e).Collection(...).Load()chủ động.
40. N+1 query problem — ví dụ?
var users = _db.Users.ToList(); // 1 query
foreach (var u in users)
Console.WriteLine(u.Orders.Count); // N query — mỗi user 1 query (lazy)
Fix: Include(u => u.Orders).
41. AsNoTracking() dùng khi nào?
Query chỉ đọc — không cần track change → nhanh hơn, ít RAM. Không gọi SaveChanges() được cho entity từ no-tracking.
42. Add vs Attach vs Update?
Add: state = Added → INSERT.Attach: state = Unchanged → không UPDATE.Update: state = Modified → UPDATE tất cả cột.
Hiểu state machine để tránh UPDATE thừa cột.
43. Migration — workflow chuẩn?
dotnet ef migrations add InitialCreate
dotnet ef database update
# Sửa entity → migration mới
dotnet ef migrations add AddUserAvatar
dotnet ef database update
# Sản xuất: sinh script SQL
dotnet ef migrations script -i -o init.sql
44. Fluent API vs Data Annotation?
- Data Annotation: gắn trên class/property (
[Required],[MaxLength]). Đơn giản. - Fluent API: trong
OnModelCreating— mạnh hơn, configurable hơn (composite key, complex index).
Tổ chức tốt: dùng IEntityTypeConfiguration<T> mỗi entity 1 file.
45. Include vs ThenInclude?
_db.Orders
.Include(o => o.Customer) // navigation cấp 1
.Include(o => o.Items) // navigation cấp 1 khác
.ThenInclude(i => i.Product); // tiếp tục từ Items
46. Raw SQL trong EF Core?
- Query:
_db.Users.FromSqlRaw("SELECT * FROM Users WHERE Age > {0}", 18). - Update/Insert/Delete:
_db.Database.ExecuteSqlRaw("UPDATE ...", params). - Phải dùng interpolated raw:
FromSqlInterpolated($"SELECT * FROM Users WHERE Id={id}")an toàn SQL injection.
47. SaveChanges() chạy bao nhiêu transaction?
1 transaction, gom mọi INSERT/UPDATE/DELETE. Nếu 1 cái fail, rollback toàn bộ.
48. EF Core có hỗ trợ split query không?
Có (.NET 5+). AsSplitQuery() — sinh nhiều SELECT thay vì 1 JOIN khổng lồ → tránh cartesian explosion khi Include nhiều navigation collection.
49. Soft delete trong EF Core?
Thêm cột IsDeleted bool + global query filter:
mb.Entity<User>().HasQueryFilter(u => !u.IsDeleted);
Mọi query tự thêm WHERE IsDeleted = 0.
50. Optimistic vs Pessimistic concurrency?
- Pessimistic: lock row khi đọc — chặn user khác sửa.
- Optimistic: không lock, dùng cột
RowVersion(timestamp). Khi SaveChanges → so version, nếu khác →DbUpdateConcurrencyException. Mặc định EF Core.
51. Connection pooling trong EF Core?
ADO.NET tự pool ở mức connection. EF Core thêm DbContext pooling:
services.AddDbContextPool<AppDbContext>(opt => opt.UseSqlServer(...));
Giảm cost tạo DbContext mỗi request.
52. Sự khác giữa Find và FirstOrDefault?
Find(id): tìm theo PK, check change tracker trước — nếu đã trong memory, không query DB.FirstOrDefault(...): luôn query DB.
53. Khi nào nên dùng Dapper thay EF Core?
- Cần performance tối đa cho query phức tạp (analytics, report).
- Cần kiểm soát SQL từng dòng.
- Project không cần full feature ORM. Dapper là micro-ORM, chỉ map result → object, không tracking.
➡️ Tiếp theo: Ngân hàng câu hỏi DSA + Coding