Tất cả chúng ta đều muốn tin rằng các ứng dụng của chúng ta không có lỗi và sẽ chạy mà không có ngoại lệ. Những nhà phát triển đã làm đủ lâu sẽ biết rằng người dùng sẽ tìm ra cách để phá vỡ các cơ sở mã được kiểm tra tỉ mỉ nhất của chúng ta. Ngoài việc kiểm tra kỹ lưỡng, chúng ta cũng nên tính đến các trường hợp ngoại lệ không mong muốn.
Trong ASP.NET Core, chúng ta có thể xử lý các ngoại lệ đó bằng cách sử dụng middleware ExceptionHandlerMiddleware
đi kèm với web framework.
Bài viết này sẽ chỉ ra cách chúng ta có thể sử dụng middleware theo hai cách khác nhau để xử lý các ngoại lệ toàn cục. Tất cả các phương pháp đều hoạt động tương tự nhau, nhưng chúng ta sẽ nói về ưu điểm của từng phương pháp và tại sao chúng ta muốn sử dụng nó cho ứng dụng của mình.
Chúng tôi sẽ giới thiệu tổng quan nhanh cho những người không quen với hoạt động bên trong của ASP.NET Core.
Ứng dụng của chúng ta sẽ xử lý tất cả các yêu cầu đến thông qua Request Pipeline (đường ống yêu cầu) mà chúng ta thường thiết lập trong phương thức Configure
của class Startup
.
ASP.NET Core sẽ gọi đường ống của chúng ta bằng cách sử dụng cái mà hầu hết các nhà phát triển gọi là Mô hình búp bê Nga. Mỗi thành phần đã đăng ký được gọi bởi thành phần trước và có khả năng gọi thành phần tiếp theo.
Request Pipeline của chúng ta có thể bao gồm các middleware (phần mềm trung gian), ASP.NET Core endpoint (điểm cuối) và các framework cấp cao như ASP.NET Core MVC.
Mỗi middleware có cơ hội xử lý yêu cầu đến, gọi middleware tiếp theo hoặc chấm dứt yêu cầu HTTP bằng cách trả về một phản hồi. Hiểu request pipeline là điều cần thiết, vì nó chỉ định nơi chúng ta nên đăng ký middleware xử lý ngoại lệ của mình.
Nếu chúng ta đăng ký middleware xử lý ngoại lệ quá muộn, thì sẽ có thể bỏ lỡ các trường hợp ngoại lệ.
Để hiểu cách xử lý một ngoại lệ (exception), trước tiên hãy tạo một endpoint hoạt động sai trong ứng dụng ASP.NET Core của chúng ta.
Trong cuộc gọi tới phương thức UseEndpoints
, chúng ta sẽ thêm một endpoint bị lỗi ngẫu nhiên. Chúng ta sẽ xem phần sau cách truy xuất ngoại lệ đã ném bằng cách sử dụng tính năng IExceptionHandlerPathFeature
.
app.UseEndpoints(endpoints =>
{
endpoints.MapRazorPages();
endpoints.MapGet("/", async context =>
{
var random = new Random();
throw random.Next(1, 4) switch
{
1 => new ArgumentException("what were you thinking?!", nameof(random)),
2 => new DataException("New exception, who dis?"),
_ => new ArithmeticException("1 + 1 is 4")
};
});
});
Khi chúng ta bắt đầu ứng dụng của mình, chúng ta nên ngay lập tức ném một trong ba trường hợp ngoại lệ được hiển thị ở trên.
Cách tiếp cận đơn giản nhất để xử lý các ngoại lệ trong ứng dụng ASP.NET Core của chúng ta là đăng ký middleware ExceptionHandlerMiddleware
bằng cách sử dụng PathString
.
Chúng ta có thể thêm middleware bằng cách gọi phương thức mở rộng UseExceptionHandler
trong phương thức Configure
của class Startup
. Hãy nhớ rằng, thứ tự của middleware là điều rất quan trọng.
Chúng ta cần thực hiện cuộc gọi đăng ký middleware xử lý ngoại lệ trước tất cả các middleware khác nếu chúng ta mong đợi trình xử lý sẽ xử lý lỗi một cách thích hợp.
app.UseExceptionHandler("/error");
Trong trường hợp này, chúng ta yêu cầu ASP.NET Core thực thi đường dẫn mà chúng ta đã cung cấp thay cho yêu cầu không thành công. Middleware ExceptionHandlerMiddleware
sẽ gửi một yêu cầu mới đến đường dẫn /error
của chúng ta.
Trong ví dụ này, chúng ta sẽ định nghĩa một trang ** Razor Pages ** tại điểm cuối /error
này.
using System;
using System.Data;
using System.Net;
using Microsoft.AspNetCore.Diagnostics;
using Microsoft.AspNetCore.Mvc.RazorPages;
namespace WebApplication8.Pages
{
public class Error : PageModel
{
public void OnGet()
{
var ctx = HttpContext;
var feature = ctx.Features.Get<IExceptionHandlerPathFeature>();
ctx.Response.StatusCode = (int) HttpStatusCode.InternalServerError;
var exception = feature.Error;
string message = exception switch
{
ArgumentException ae => $"{ae.ParamName} & {ae.Message}",
DataException de => $"{de.Message}",
ArithmeticException are => $"{are.Message}",
_ => "oops!"
};
Message = message;
}
public string Message { get; set; }
}
}
Razor Page của chúng ta có thể truy xuất ngoại lệ bằng cách sử dụng tính năng IExceptionHandlerPathFeature
. Chúng ta có thể truy xuất tính năng từ danh sách HttpContext.Features
, tại thời điểm đó chúng ta cũng có quyền truy cập vào tính năng Exception
mà ứng dụng của chúng ta đã ném ra.
Ưu điểm đáng kể nhất của cách tiếp cận này là tính đơn giản của nó. Trình xử lý ngoại lệ không phụ thuộc vào bất kỳ framework nào nằm ở đầu kia của đường dẫn.
ASP.NET Core MVC, Carter hoặc các framework khác có thể sẵn sàng để xử lý ngoại lệ. Trong ví dụ của chúng ta, chúng ta đã sử dụng Razor Pages để hiển thị thông báo lỗi.
Ưu điểm bổ sung là trình xử lý thực thi tại chỗ, bảo toàn đường dẫn yêu cầu cho máy khách.
Điểm bất lợi đáng kể nhất là trình xử lý ngoại lệ sẽ sử dụng lại định nghĩa đường ống hiện có nơi xảy ra lỗi.
Ngoại lệ có thể đã xảy ra do một thành phần middleware được cấu hình sai. Nếu trường hợp này xảy ra, chúng ta có thể bị mắc kẹt trong trạng thái xử lý lỗi đệ quy, do đó phá vỡ ứng dụng của chúng ta.
Mặc dù có thể không xảy ra trường hợp này, nhưng vẫn có khả năng các nhà phát triển ASP.NET Core sẽ cần lưu ý. Vậy chúng ta có thể làm gì về vấn đề này?
Một tính năng ít được biết đến của phương thức UseExceptionHandler
là nó có nhiều phương thức quá tải. Một trong những phương thức quá tải đó có một đối số là interface IApplicationBuilder
, điều này cho phép chúng ta định nghĩa lại một request pipeline riêng biệt.
Tại đây chúng ta có thể thêm hoặc bớt middleware có thể là nguồn gốc của các trường hợp ngoại lệ. Hãy xem nó trong đoạn mã dưới đây.
// define exception handler pipeline this will create a brand
// new pipeline separate from the original failed pipeline
app.UseExceptionHandler(builder =>
{
// define brand new pipeline
builder.Use(async (ctx, next) =>
{
var feature = ctx.Features.Get<IExceptionHandlerPathFeature>();
ctx.Response.StatusCode = (int) HttpStatusCode.InternalServerError;
var exception = feature.Error;
string message = exception switch
{
ArgumentException ae => $"{ae.ParamName} & {ae.Message}",
DataException de => $"{de.Message}",
ArithmeticException are => $"{are.Message}",
_ => "oops!"
};
await ctx.Response.WriteAsync(message);
});
});
Trong đoạn mã trên, chúng ta định nghĩa đường dẫn của chúng ta là một RequestDelegate
duy nhất, không đề cập đến các framework hoặc middleware khác.
Ưu điểm đáng kể nhất của cách tiếp cận này là khả năng định nghĩa một đường ống được sắp xếp hợp lý cho các trường hợp ngoại lệ.
Phương pháp này hữu ích để giảm thiểu sự xuất hiện của các lỗi tiếp theo và giảm lượng thời gian cần thiết để phản hồi với một ngoại lệ. Càng ít middleware, càng ít cuộc gọi đến các phương thức cần thực thi.
Bất lợi đáng kể nhất là cần phải định nghĩa lại đường ống mới. Trong khi định nghĩa lại đường ống mới, chúng ta có thể quên bao gồm một số phần quan trọng trong ứng dụng của chúng ta. Tệ hơn nữa, chúng ta có thể vô tình hoán đổi thứ tự hai middleware, tạo ra một lỗi thứ tự rất tinh vi.
Trong bài viết này, chúng ta đã chỉ ra hai cách xử lý ngoại lệ bằng cách sử dụng middleware ExceptionHandlerMiddleware
và đối với hầu hết mọi người, phương pháp sử dụng PathString
là lựa chọn tốt nhất. Chúng ta có thể định nghĩa đường dẫn xử lý ngoại lệ của mình bằng cách sử dụng các cách tiếp cận yêu thích của chúng ta.
Bài viết này cho thấy cách truy cập tính năng IExceptionHandlerPathFeature
cho phép chúng ta truy cập vào ngoại lệ đã làm gián đoạn yêu cầu của chúng ta.
Cuối cùng, chúng ta đã sử dụng một phương thức quá tải UseExceptionHandler
để định nghĩa lại đường dẫn yêu cầu của chúng ta nhằm giảm nguy cơ thất bại khi xử lý một yêu cầu không thành công.
Tôi hy vọng bạn thấy bài viết này hữu ích và vui lòng để lại nhận xét về cách bạn sử dụng middleware ExceptionHandlerMiddleware
trong các ứng dụng của mình.
Bạn có thể vui lòng tắt trình chặn quảng cáo ❤️ để hỗ trợ chúng tôi duy trì hoạt động của trang web.
Trong bài viết này, tôi giới thiệu sơ lược về một số lựa chọn thay thế cho thư viện Microsoft.FeatureManagement và mô tả sự khác biệt của chúng
Trong bài viết này, tôi giới thiệu hai cách để cải thiện tính nhất quán của cờ tính năng cho mọi yêu cầu đối với người dùng trong ứng dụng ASP.NET Core.
Trong bài viết này, tôi sẽ chỉ cho bạn cách tạo bộ lọc tính năng tùy chỉnh của riêng mình bằng cách sử dụng IFeatureFilter trong ASP.NET Core.
Trong bài này, tôi sẽ hướng dẫn cách sử dụng hai bộ lọc PercentageFilter và TimeWindowFilter để tạo cờ tính năng động trong ứng dụng ASP.NET Core.