2015-02-24 9 views
11

Pisałem prosty serwer używając Owin Self-hosting i WebAPI:Jak przesłonić domyślne nieobsługiwane wyjście wyjątku w 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(); 
     } 
    } 

} 

Gdy istnieje wyjątek w sterowniku, następnie Owin zwraca odpowiedź XML tak:

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

Ale chcę innego wyjścia - więc jak mogę to zmienić?

+1

Jakie wyjście szukasz? – abatishchev

Odpowiedz

8

to zrobić poprzez stworzenie OWIN Middleware i podpinania go do rurociągu:

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 
     } 
    } 
} 

i zaczepić go na starcie:

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); 
    } 
} 

ten sposób wszystkie nieobsługiwane wyjątki zostanie złapany przez middleware i pozwala dostosować wynik wyjściowy.

Ważną rzeczą, aby pamiętać: jeżeli sprawa ma być obsługiwany wyjątek obsługi logikę jego własne, podobnie jak WebAPI, wyjątki nie będą propagować. Ten program obsługi jest przeznaczony dla każdego wyjątku, który przechodzi przez unhandeled przez bazową usługę hostowaną pod numerem.

+0

@DarthVader - Co dokładnie nie działa? –

+7

Przy okazji, to nie działa. Po wywołaniu Next.Invoke() blok catch nigdy nie zostanie wyzwolony. Natknąłem się na to podczas moich poszukiwań byłoby miło wiedzieć, jak to zrobić. Wyjątek jest połknięty, nie pojawia się kontekst ani słownik. –

+0

@DrSchizo No cóż, jeśli twój wyjątek jest dostarczany przez WebAPI, oczywiście nie zobaczysz, że trafiasz tutaj, ponieważ jest już dostarczony i zawarty w tym środowisku. –

2

Podczas oczekiwania na metodę asynchroniczną wyjątek nie zostanie zgłoszony w kontekście dzwoniącego, ale będzie dostępny poprzez sprawdzenie zadania zwróconego do osoby dzwoniącej.

Tak, z tej modyfikacji do rozwiązania przewidzianego przez @ yuval-itzchakov będziesz w stanie przechwytywać wyjątki podstawowych:

var subtask = Next.Invoke(context); 

await subtask; 

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

Jeśli 'Task' lub' Task 'zgłasza wyjątek, to z pewnością będzie propagować w punkcie' czekania'. Jak myślisz, dlaczego by tak nie było? –

Powiązane problemy