bắt tất cả các ngoại lệ không được xử lý trong ASP.NET Web Api


113

Làm cách nào để bắt tất cả các ngoại lệ không được xử lý xảy ra trong ASP.NET Web Api để tôi có thể ghi lại chúng?

Cho đến nay tôi đã thử:

  • Tạo và đăng ký ExceptionHandlingAttribute
  • Triển khai một Application_Errorphương pháp trongGlobal.asax.cs
  • Đăng ký AppDomain.CurrentDomain.UnhandledException
  • Đăng ký TaskScheduler.UnobservedTaskException

Các ExceptionHandlingAttributexử lý thành công trường hợp ngoại lệ được ném trong phương pháp hành động điều khiển và bộ lọc hành động, nhưng trường hợp ngoại lệ khác không được xử lý, ví dụ:

  • Các ngoại lệ được ném ra khi một IQueryablephương thức hành động trả về không thực thi được
  • Các ngoại lệ do một trình xử lý tin nhắn ném ra (tức là HttpConfiguration.MessageHandlers)
  • Các ngoại lệ được ném ra khi tạo một phiên bản bộ điều khiển

Về cơ bản, nếu một ngoại lệ sẽ gây ra Lỗi máy chủ nội bộ 500 được trả lại cho máy khách, tôi muốn nó được ghi lại. Việc triển khai Application_Errorđã làm tốt công việc này trong Web Forms và MVC - tôi có thể sử dụng gì trong Web Api?


Bạn đã thử sử dụng Theo dõi sức khỏe ASP.NET chưa? Chỉ cần kích hoạt nó và xem liệu các ngoại lệ của bạn có được ghi vào nhật ký sự kiện hay không.
John Saunders

Theo dõi sức khỏe bắt các ngoại lệ đường ống MVC của tôi, nhưng không bắt các ngoại lệ đường ống Web Api của tôi.
Joe Daley

Cảm ơn - Tôi đã mất một thời gian để tìm hiểu tại sao tôi không thể đăng nhập vấn đề xây dựng / dependency injection của tôi, nơi tôi nghĩ tôi đã có WebAPI khai thác gỗ được sắp xếp đã ...
Overflew

Câu trả lời:


156

Điều này hiện có thể thực hiện được với WebAPI 2.1 (xem Có gì mới ):

Tạo một hoặc nhiều triển khai IExceptionLogger. Ví dụ:

public class TraceExceptionLogger : ExceptionLogger
{
    public override void Log(ExceptionLoggerContext context)
    {
        Trace.TraceError(context.ExceptionContext.Exception.ToString());
    }
}

Sau đó đăng ký với HttpConfiguration của ứng dụng của bạn, bên trong một lệnh gọi lại cấu hình như sau:

config.Services.Add(typeof(IExceptionLogger), new TraceExceptionLogger());

hoặc trực tiếp:

GlobalConfiguration.Configuration.Services.Add(typeof(IExceptionLogger), new TraceExceptionLogger());

7
@NeilBarnwell Có, Web API 2.1 tương ứng với phiên bản hợp ngữ System.Web.Http 5.1.0 . Vì vậy, bạn cần phiên bản này trở lên để sử dụng giải pháp được mô tả ở đây. Xem các phiên bản gói
nuget

2
Một số lỗi 500 vẫn không bị lỗi này, ví dụ: HttpException - máy chủ từ xa đã đóng kết nối. Có chỗ nào để global.asax Application_Error xử lý các lỗi bên ngoài xử lý api web không?
Avner

11
Tôi thích mức độ chi tiết của doco chính thức trên msdn và điều mà 99% nhà phát triển thực sự muốn chỉ là 8 dòng mã để ghi lỗi.
Rocklan

20

Câu trả lời của Yuval là để tùy chỉnh phản hồi đối với các trường hợp ngoại lệ không được khắc phục bởi API Web, không phải để ghi nhật ký, như đã lưu ý trên trang liên kết . Tham khảo phần Khi nào sử dụng trên trang để biết thêm chi tiết. Trình ghi nhật ký luôn được gọi nhưng trình xử lý chỉ được gọi khi có thể gửi phản hồi. Tóm lại, sử dụng trình ghi nhật ký để ghi nhật ký và trình xử lý để tùy chỉnh phản hồi.

Nhân tiện, tôi đang sử dụng assembly v5.2.3 và ExceptionHandlerlớp không có HandleCorephương thức. Tương đương, tôi nghĩ, là Handle. Tuy nhiên, chỉ cần phân lớp con ExceptionHandler(như trong câu trả lời của Yuval) không hoạt động. Trong trường hợp của tôi, tôi phải thực hiện IExceptionHandlernhư sau.

internal class OopsExceptionHandler : IExceptionHandler
{
    private readonly IExceptionHandler _innerHandler;

    public OopsExceptionHandler (IExceptionHandler innerHandler)
    {
        if (innerHandler == null)
            throw new ArgumentNullException(nameof(innerHandler));

        _innerHandler = innerHandler;
    }

    public IExceptionHandler InnerHandler
    {
        get { return _innerHandler; }
    }

    public Task HandleAsync(ExceptionHandlerContext context, CancellationToken cancellationToken)
    {
        Handle(context);

        return Task.FromResult<object>(null);
    }

    public void Handle(ExceptionHandlerContext context)
    {
        // Create your own custom result here...
        // In dev, you might want to null out the result
        // to display the YSOD.
        // context.Result = null;
        context.Result = new InternalServerErrorResult(context.Request);
    }
}

Lưu ý rằng, không giống như trình ghi nhật ký, bạn đăng ký trình xử lý của mình bằng cách thay thế trình xử lý mặc định, không thêm.

config.Services.Replace(typeof(IExceptionHandler),
    new OopsExceptionHandler(config.Services.GetExceptionHandler()));

1
Đây là một giải pháp tuyệt vời, đây phải là giải pháp được chấp nhận để 'bắt hoặc ghi lại tất cả các lỗi'. Tôi có thể chưa bao giờ tìm ra lý do tại sao nó không hoạt động với tôi khi tôi vừa mở rộng ExceptionHandler.
Rajiv

Giải pháp tuyệt vời. Khi đường ống MVC đã được tải cho một yêu cầu, điều này hoạt động tốt. IIS vẫn xử lý các ngoại lệ cho đến lúc đó, kể cả khi quay OWIN trong startup.cs. Tuy nhiên, tại một số thời điểm sau khi spin up kết thúc quá trình xử lý startup.cs, nó thực hiện công việc một cách tuyệt vời.
Gustyn

18

Để trả lời câu hỏi của riêng tôi, điều này là không thể!

Xử lý tất cả các trường hợp ngoại lệ gây ra lỗi máy chủ nội bộ dường như là một khả năng cơ bản của API Web nên có, vì vậy tôi đã đưa ra yêu cầu với Microsoft về trình xử lý lỗi Toàn cầu cho API Web :

https://aspnetwebstack.codeplex.com/workitem/1001

Nếu bạn đồng ý, hãy vào liên kết đó và bình chọn cho nó!

Trong khi đó, bài viết tuyệt vời về Xử lý ngoại lệ API Web ASP.NET chỉ ra một số cách khác nhau để bắt một số loại lỗi khác nhau. Nó phức tạp hơn mức bình thường và nó không bắt được tất cả các lỗi máy chủ nội bộ, nhưng đó là cách tiếp cận tốt nhất hiện nay.

Cập nhật: Xử lý lỗi toàn cầu hiện đã được triển khai và có sẵn trong các bản dựng hàng đêm! Nó sẽ được phát hành trong ASP.NET MVC v5.1. Đây là cách nó sẽ hoạt động: https://aspnetwebstack.codeplex.com/wikipage?title=Global%20Error%20Handling


có vẻ như một lý do để điều khiển sử dụng cho các cuộc gọi ajax thay vì api web .. ranh giới đã mờ .. mặc dù nếu ELMAH có thể nắm bắt nó, có lẽ có một cách
Sonic linh hồn

4
Xử lý lỗi toàn cầu hiện đã được thêm vào Web API 2.1. Xem câu trả lời của tôi để biết thêm chi tiết.
decates

10

Bạn cũng có thể tạo một trình xử lý ngoại lệ chung bằng cách triển khai IExceptionHandlergiao diện (hoặc kế thừa ExceptionHandlerlớp cơ sở). Nó sẽ là lần cuối cùng được gọi trong chuỗi thực thi, sau khi tất cả đã được đăng ký IExceptionLogger:

IExceptionHandler xử lý tất cả các ngoại lệ chưa được xử lý từ tất cả các bộ điều khiển. Đây là cuối cùng trong danh sách. Nếu một ngoại lệ xảy ra, IExceptionLogger sẽ được gọi đầu tiên, sau đó là bộ điều khiển ExceptionFilters và nếu vẫn chưa được xử lý, thì việc triển khai IExceptionHandler.

public class OopsExceptionHandler : ExceptionHandler
{
    public override void HandleCore(ExceptionHandlerContext context)
    {
        context.Result = new TextPlainErrorResult
        {
            Request = context.ExceptionContext.Request,
            Content = "Oops! Sorry! Something went wrong."        
        };
    }

    private class TextPlainErrorResult : IHttpActionResult
    {
        public HttpRequestMessage Request { get; set; }

        public string Content { get; set; }

        public Task<HttpResponseMessage> ExecuteAsync(CancellationToken cancellationToken)
        {
            HttpResponseMessage response = 
                             new HttpResponseMessage(HttpStatusCode.InternalServerError);
            response.Content = new StringContent(Content);
            response.RequestMessage = Request;
            return Task.FromResult(response);
        }
    }
}

Thêm về điều đó ở đây .


Chỉ tò mò, đây là nơi đăng ký?
ThunD3eR

-1

Bạn có thể có các khối thử bắt hiện tại mà bạn không biết.

Tôi nghĩ rằng global.asax.Application_Errorphương pháp mới của tôi không được gọi một cách nhất quán cho các trường hợp ngoại lệ không được khắc phục trong mã kế thừa của chúng tôi.

Sau đó, tôi tìm thấy một vài khối try-catch ở giữa ngăn xếp cuộc gọi có tên là Response.Write trên văn bản Exception. Điều đó là vậy đó. Đổ văn bản trên màn hình sau đó giết chết viên đá ngoại lệ.

Vì vậy, các trường hợp ngoại lệ đã được xử lý, nhưng việc xử lý không có ích gì. Sau khi tôi loại bỏ các khối try-catch đó, các ngoại lệ được truyền cho phương thức Application_Error như mong đợi.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.