2012-08-08 33 views
13

Tôi có một ExceptionFilter toàn cầu trong MVC của tôi \ WebAPI đơn đăng ký như:Làm thế nào để một cách duyên dáng trở lại ngoại lệ từ một WebAPI nhắn Handler

public virtual void RegisterHttpFilters(HttpConfiguration config) 
{ 
    config.Filters.Add(new MyExceptionFilter(_exceptionHandler)); 
} 

nơi MyExceptionFilter là:

public class MyExceptionFilter : ExceptionFilterAttribute 
{ 
    private readonly IMyExceptionHandler m_exceptionHandler; 

    public MyExceptionFilter(IMyExceptionHandler exceptionHandler) 
    { 
     m_exceptionHandler = exceptionHandler; 
    } 

    public override void OnException(HttpActionExecutedContext context) 
    { 
     Exception ex = context.Exception; 
     if (ex != null) 
     { 
      object response = null; 
      HttpStatusCode statusCode = m_exceptionHandler != null 
       ? m_exceptionHandler.HandleException(ex, out response) 
       : HttpStatusCode.InternalServerError; 
      context.Response = context.Request.CreateResponse(statusCode, response ?? ex); 
     } 

     base.OnException(context); 
    } 
} 

Bộ lọc này trả về tất cả trường hợp ngoại lệ là đối tượng json và cho phép một số triển khai IMyExceptionHandler tùy chỉnh đối tượng được trả về.

Tất cả điều này hoạt động tốt. Cho đến khi tôi có ngoại lệ trong một số trình xử lý tin nhắn của mình:

public class FooMessageHandler : DelegatingHandler 
{ 
    private readonly Func<IBar> _barFactory; 
    public FooMessageHandler(Func<IBar> barFactory) 
    { 
     _barFactory = varFactory; 
    } 

    protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) 
    { 
     request.Properties["MY_BAR"] = _barFactory(); 
     return base.SendAsync(request, cancellationToken); 
    } 
} 

Như bạn có thể thấy trình xử lý này tạo một số thành phần và đưa nó vào thông báo yêu cầu http hiện tại. Khi một ngoại lệ xảy ra trong FuncOfIBar sau đó tôi nhận được màn hình màu vàng của cái chết. ExceptionFilter của tôi không được gọi.

tôi cố gắng đặc biệt bắt ngoại lệ trong xử lý tin nhắn và trở HttpResponseException nhưng nó không thay đổi bất cứ điều gì - vẫn nhận được YSOD:

public class XApplicationInitializerMessageHandler : DelegatingHandler 
{ 
    private readonly Func<IXCoreApplication> _appFactory; 
    private readonly IXExceptionHandler m_exceptionHandler; 

    public XApplicationInitializerMessageHandler(Func<IXCoreApplication> appFactory, IXExceptionHandler exceptionHandler) 
    { 
     ArgumentValidator.EnsureArgumentNotNull(appFactory, "appFactory"); 
     _appFactory = appFactory; 
     m_exceptionHandler = exceptionHandler; 
    } 

    protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) 
    { 
     try 
     { 
      request.SetApplication(_appFactory()); 
     } 
     catch (Exception ex) 
     { 
      object resultObject = null; 
      HttpStatusCode statusCode = m_exceptionHandler != null 
       ? m_exceptionHandler.HandleException(ex, out resultObject) 
       : HttpStatusCode.InternalServerError; 
      HttpResponseMessage responseMessage = request.CreateResponse(statusCode, resultObject ?? ex); 

      throw new HttpResponseException(responseMessage); 
     } 
     return base.SendAsync(request, cancellationToken); 
    } 
} 

}

Tôi muốn hành vi của ứng dụng của tôi là tương tự bất kể nơi một ngoại lệ xảy ra: trong một ApiController hoặc một trình xử lý tin nhắn.

Cách thực hiện việc này?

Tôi biết về Application_Error nhưng tôi muốn giữ tùy chỉnh HttpApplication không thể chạm tới.

+0

http://stackoverflow.com/questions/13013973/asp-net-web-api-mặc định-lỗi-tin nhắn – Timeless

Trả lời

8

Thay vì ném HttpResponseException tôi chỉ phải trả lại một HttpResponseMessage:

protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) 
{ 
    try 
    { 
     request.SetApplication(_appFactory()); 
    } 
    catch (Exception ex) 
    { 
     object resultObject = null; 
     HttpStatusCode statusCode = m_exceptionHandler != null 
      ? m_exceptionHandler.HandleException(ex, out resultObject) 
      : HttpStatusCode.InternalServerError; 
     HttpResponseMessage responseMessage = request.CreateResponse(statusCode, resultObject ?? ex); 

     return Task<HttpResponseMessage>.Factory.StartNew(() => responseMessage); 
    } 
    return base.SendAsync(request, cancellationToken); 
} 
5

Những gì tôi đã làm với succes đang sử dụng một cách tiếp cận dựa trên thuộc tính. Bạn đặt một thuộc tính tùy chỉnh trên mỗi hành động mà nên sử dụng xử lý ngoại lệ:

[ExceptionHandling] 
public IEnumerable<string> Get() 

tùy chỉnh xử lý ngoại lệ thuộc tính của bạn được thực hiện như thế này:

public class ExceptionHandlingAttribute : ExceptionFilterAttribute 
{ 
    public override void OnException(HttpActionExecutedContext context) 
    {} 

Như bạn có thể nhìn thấy bạn, các thuộc tính tùy chỉnh là được thừa hưởng từ ExceptionFilterAttribute. Sau đó bạn chỉ cần ghi đè phương thức OnException. Những gì bạn có thể làm là xem xét loại ngoại lệ và xử lý nó theo các quy tắc kinh doanh hoặc những gì phù hợp với nhu cầu của bạn. Trong một số trường hợp, bạn có thể chỉ nuốt ngoại lệ trên máy chủ. Nếu bạn muốn thông báo cho khách hàng, bạn có thể ném một HttpResponseException, có thể chứa tất cả thông tin liên quan, chẳng hạn như tin nhắn, ngăn xếp cuộc gọi, ngoại lệ bên trong, v.v.

Để có thêm cảm hứng, hãy xem bài đăng tuyệt vời trên blog này: ASP.NET Web API Exception Handling

5

Tôi gặp vấn đề tương tự với bộ lọc ngoại lệ chung không chạy. Giải pháp là các bộ lọc ngoại lệ Web API phải được cấu hình trong một bộ sưu tập toàn cục khác với các bộ lọc ngoại lệ ASP.NET MVC.

Vì vậy, để định cấu hình ASP.NET MVC xử lý lỗi bạn sẽ chạy:

System.Web.Mvc.GlobalFilters.Filters.Add(new MyMvcExceptionFilter()); 

Nhưng đối với lỗi Web API xử lý, bạn phải chạy:

System.Web.Http.GlobalConfiguration.Configuration.Filters.Add(new MyWebApiExceptionFilter()); 

Từ kinh nghiệm hạn chế của tôi với Web API kiểu này tình hình là điển hình: một cách hời hợt các mô hình sử dụng sẽ rất giống với ASP.NET MVC và vì vậy ngay lập tức quen thuộc. Điều này cho thấy ảo giác rằng viết một đoạn mã sẽ có tác dụng trên cả hai khung, nhưng thực sự việc triển khai của chúng bên dưới tất cả là phần lớn hoặc hoàn toàn riêng biệt và bạn sẽ cần phải viết hai phiên bản của mã rất giống với công việc.

xuất sắc tham khảo về xử lý ngoại lệ Web API: http://www.asp.net/web-api/overview/web-api-routing-and-actions/exception-handling

2

Trong startup.cs:

config.Services.Replace(typeof(IExceptionHandler), new GlobalExceptionHandler()); 

tôi thấy rằng việc sử dụng GlobalExceptionHandler có thể bắt ngoại trừ trong ủy xử lý và trả lại đối tượng JSON tùy chỉnh.

0

Tôi tìm thấy blog này với ví dụ rất tốt: http://nodogmablog.bryanhogan.net/2016/07/getting-web-api-exception-details-from-a-httpresponsemessage/

tôi đã thông qua mã với một số cập nhật:

if ((int)response.StatusCode >= 400) 
{ 
     exceptionResponse = JsonConvert.DeserializeObject<ExceptionResponse>(LogRequisicao.CorpoResposta); 
     LogRequisicao.CorpoResposta = exceptionResponse.ToString() ; 
     if (exceptionResponse.InnerException != null) 
      LogRequisicao.CorpoResposta += "\r\n InnerException: " + exceptionResponse.ToString(); 
} 

sử dụng đối tượng:

public class ExceptionResponse 
    { 
     public string Message { get; set; } 
     public string ExceptionMessage { get; set; } 
     public string ExceptionType { get; set; } 
     public string StackTrace { get; set; } 
     public ExceptionResponse InnerException { get; set; } 

     public override String ToString() 
     { 
      return "Message: " + Message + "\r\n " 
       + "ExceptionMessage: " + ExceptionMessage + "\r\n " 
       + "ExceptionType: " + ExceptionType + " \r\n " 
       + "StackTrace: " + StackTrace + " \r\n ";   
     } 
    } 
Các vấn đề liên quan