For English version: [ASPNET Core 2] – Middleware
Đôi khi bạn có một yêu cầu éo le: Viết Hello world bằng ASP.NET
Dễ ẹt, dotnet new mvc
, rồi sửa Views/Home/Index.cshtml
cho nó trả về 1 dòng
<p>hello world</p>
Thế là xong, phải ko? Có cách khác 😀
1. Middleware là giề
Tưởng tượng rằng ứng dụng asp.net của bạn là 1 đường ống nước. Data chính là nước. Nước ở đầu ống (request) thì bẩn như kênh nhiêu lộc. Bạn mong muốn rằng nước ở cuối ống (response) phải sạch như nước khoáng Lavie. Chắc phải có lọc gì đó ở giữa ống nhể?
Middleware chính là loại lọc đó. Nó gắn vào ứng dụng để xử lý requests và responses
middleware có thể quyết định là nó có tiếp tục truyền cái request nó đã xử lý cho 1 middleware tiếp theo hay ko. Trong trường hợp nó ngắt luôn ko truyền, thì ta gọi đó là
short-circuit
2. Các loại middleware
Có 3 loại middleware, phân loại bằng cách bạn implement nó như nào
Loại | Có thể short-circuit | Dùng để |
---|---|---|
Use | Có | Short-circuit một request Logic để tạo response |
Run | Không | Kết thúc pipeline |
Map MapWhen | Không | Phân nhánh pipeline dựa trên request path MapWhen phân nhánh dựa trên điều kiện Hỗ trợ Nesting (multi-level branching) |
So sánh với đồ cổ ASP.NET MVC5
ASP.NET MVC5 ASP.NET Core 2 Khái niệm HTTP Handlers
HTTP Modulesmiddleware Lựa chọn? HTTP Handlers => Dựa trên filename extension
HTTP Modules => Móc vào life cycle bằng cách dùng eventsĐịnh nghĩa theo 1 thứ tự đặc biệt và các từ khóa
Run => kết thúc pipeline
Use => short-circuit và xử lý logic
Map => phân nhánh dựa trên pathDễ xài ko? Đòi hỏi hiểu sâu về ASP.NET life-cycle
Khó xài vì nhiều modules có thể móc vào cùng 1 eventYêu cầu 1 thứ tự nhất định
Chỉ có 1 dòng pipeline, dễ hiểu/xài/debug
3. Default middleware
Khi mới tạo 1 project asp.net core mới, .net cli sẽ thêm vào 1 số middleware cho bạn
- Exception Handler: handle exception từ các middleware ở dưới
- Static Files: trả về files trong wwwroots
- Mvc: Hướng request tới các action trong controller
source code nè
public static void Configure(IApplicationBuilder app, IHostingEnvironment env) { if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } else { app.UseExceptionHandler("/Error/500"); } app.UseStaticFiles(); app.UseAuthentication(); app.UseSession(); if (!env.IsDevelopment()) { app.UseMiddleware<ErrorHandlingMiddleware>(); } app.UseMvc(routes => { routes.MapRoute( name: "default", template: "{controller=Home}/{action=Index}/{id?}"); }); }
Đây danh sách các built-in middlewares
4. Viết một middleware
4.1. Dùng delegate
thêm code vào Startup.cs
, method Configure
app.Use((context, next) => { var cultureQuery = context.Request.Query["culture"]; if (!string.IsNullOrWhiteSpace(cultureQuery)) { var culture = new CultureInfo(cultureQuery); CultureInfo.CurrentCulture = culture; CultureInfo.CurrentUICulture = culture; } // Call the next delegate/middleware in the pipeline return next(); });
4.2. Xài class riêng
phức tạp hơn, nhưng bù lại linh hoạt hơn
đầu tiên, code cho middleware
public class RequestCultureMiddleware { private readonly RequestDelegate _next; public RequestCultureMiddleware(RequestDelegate next) { _next =next; } public Task InvokeAsync(HttpContext context) { var cultureQuery = context.Request.Query["culture"]; if (!string.IsNullOrWhiteSpace(cultureQuery)) { var culture = new CultureInfo(cultureQuery); CultureInfo.CurrentCulture = culture; CultureInfo.CurrentUICulture = culture; } // Call the next delegate/middleware in the pipeline return this._next(context); } }
sau đó, code cho extension để xài được middleware đó trong method Configure
// Expose through IApplicationBuilder public static class RequestCultureMiddlewareExtensions { public static IApplicationBuilder UseRequestCulture(this IApplicationBuilder builder) { return builder.UseMiddleware<RequestCultureMiddleware>(); } }
cuối cùng, xài trong Configure
method
// Use in Startup.cs => Configure method public void Configure(IApplicationBuilder app) { app.UseRequestCulture(); app.Run(async (context) => { await context.Response.WriteAsync($"Hello{CultureInfo.CurrentCulture.DisplayName}"); }); }
ghi chú khi xài Dependency Injection
Scoped lifetime service
phải được inject vào Invoke hoặc InvokeAsync methodInject cái
scoped lifetime service
thông qua constructor sẽ ép cái service đó thành singleton
có 3 loại lifetime cho một service trong asp.net, là transient
, scoped
và singleton
-
Transient lifetime services được tạo ra mỗi lần nó được gọi. Loại này phù hợp cho các service lightweight, stateless.
-
Scoped lifetime services được tạo cho mỗi request.
-
Singleton lifetime services được tạo cho lần requested đầu tiên (hoặc khi ConfigureServices khởi chạy nếu bạn có tạo 1 instance của service trong đó) rồi các request sau đó sẽ xài lại instance này.
Good!
LikeLike
The Run method is used to add middleware and immediately return a response, thus short-circuiting the request pipeline. It does not call any of the following middlewares and ends the request pipeline. It is therefore advised to place it at the end of your middleware calls (see middleware ordering, discussed previously).
LikeLike