2015-02-24 36 views
11

我一直在使用Owin自託管和的WebAPI寫簡單的服務器:如何覆蓋Owin中的默認未處理異常輸出?

namespace OwinSelfHostingTest 
{ 
    using System.Threading; 
    using System.Web.Http; 
    using Microsoft.Owin.Hosting; 
    using Owin; 

    public class Startup 
    { 
     public void Configuration(IAppBuilder builder) 
     { 
      var config = new HttpConfiguration(); 

      config.Routes.MapHttpRoute(
       "Default", 
       "{controller}/{id}", 
       new { id = RouteParameter.Optional } 
       ); 

      builder.UseWebApi(config); 
     } 
    } 

    public class Server 
    { 
     private ManualResetEvent resetEvent = new ManualResetEvent(false); 
     private Thread thread; 

     private const string ADDRESS = "http://localhost:9000/"; 

     public void Start() 
     { 
      this.thread = new Thread(() => 
       { 
        using (var host = WebApp.Start<Startup>(ADDRESS)) 
        { 
         resetEvent.WaitOne(Timeout.Infinite, true); 
        } 
       }); 
      thread.Start(); 
     } 

     public void Stop() 
     { 
      resetEvent.Set(); 
     } 
    } 

} 

當在控制器例外,那麼Owin返回類似這樣的XML響應:

<Error> 
    <Message>An error has occurred.</Message> 
    <ExceptionMessage>Attempted to divide by zero.</ExceptionMessage> 
    <ExceptionType>System.DivideByZeroException</ExceptionType> 
    <StackTrace> 
     ... 
    </StackTrace> 
</Error> 

但我想不同的輸出 - 那麼我怎麼能覆蓋這個?

public class CustomExceptionMiddleware : OwinMiddleware 
{ 
    public CustomExceptionMiddleware(OwinMiddleware next) : base(next) 
    {} 

    public override async Task Invoke(IOwinContext context) 
    { 
     try 
     { 
      await Next.Invoke(context); 
     } 
     catch(Exception ex) 
     { 
      // Custom stuff here 
     } 
    } 
} 

並把它掛在啓動時:

+1

你在找什麼樣的產出? – abatishchev 2015-02-24 05:56:18

回答

8

通過創建一個OWIN中間件和它掛鉤到管道這麼做

public class Startup 
{ 
    public void Configuration(IAppBuilder builder) 
    { 
     var config = new HttpConfiguration(); 

     config.Routes.MapHttpRoute(
      "Default", 
      "{controller}/{id}", 
      new { id = RouteParameter.Optional } 
      ); 

     builder.Use<CustomExceptionMiddleware>().UseWebApi(config); 
    } 
} 

這樣,任何未處理的異常會被你的中間件被抓並允許您自定義輸出結果。

一個重要的事情要注意:如果事情被託管有一個異常處理它自己的邏輯,做的WebAPI,異常將不會傳播。此處理程序適用於由承載的基礎服務未提供的發生的任何異常。

+0

@DarthVader - 什麼不工作? – 2015-07-27 13:24:32

+7

順便說一句,這是行不通的。在調用Next.Invoke()時,catch塊永遠不會被觸發。在我的搜索中遇到這個問題很好,知道如何做到這一點。吞下的異常不會出現上下文或字典。 – 2015-12-16 17:39:55

+0

@DrSchizo那麼,如果你的異常被WebAPI控制,當然你不會看到它打到這裏,因爲它已經被綁定並且被包含在所述框架中。 – 2016-09-21 04:48:57

2

當您等待異步方法時,將不會將異常拋出到調用者的上下文中,但可通過檢查返回給調用者的任務來使用該異常。

所以,這個修改由@提供的解決方案尤瓦爾 - itzchakov你就可以捕捉到潛在的例外:

var subtask = Next.Invoke(context); 

await subtask; 

if (subtask.Exception != null) 
{ 
    // log subtask.Exception here 
} 
+1

如果「任務」或「任務」引發異常,它肯定會在'await'點傳播。你爲什麼認爲它不會? – 2016-09-21 04:55:02