2014-07-03 7 views
5

Stiamo creando un WebApi che stiamo ospitando utilizzando Owin. In precedenza abbiamo utilizzato HttpResponseException per la restituzione dei codici di stato 404 ecc. Nelle azioni del nostro controller e ha funzionato bene.Lancio HttpResponseException dal controller WebApi quando si utilizza l'host automatico Owin

Tuttavia, quando abbiamo iniziato a lavorare con Owin (self hosted) abbiamo riscontrato un problema con questo approccio che ha portato alla serializzazione di HttpResponseException su json/xml e al codice di stato da 404 a 500 (Errore interno del server) . Ecco il codice che abbiamo:

public class InvoicesController : ApiController 
{ 
    private readonly IInvoiceRepository _invoiceRepository; 

    public InvoicesController(IInvoiceRepository invoiceRepository) 
    { 
     _invoiceRepository = invoiceRepository; 
    } 

    [HttpGet] 
    public IEnumerable<AccountCodeAssignment> AssignAccountCodesToInvoiceById(int id) 
    { 
     var invoice = _invoiceRepository.Get(id); 

     if (invoice == null) throw new HttpResponseException(Request.CreateErrorResponse(HttpStatusCode.NotFound, "Invoice not found")); 

     yield return new AccountCodeAssignment(1, ...); 
     yield return new AccountCodeAssignment(2, ...); 
     yield return new AccountCodeAssignment(3, ...); 
     yield return new AccountCodeAssignment(4, ...); 
    } 
} 

e questa è la risposta torniamo insieme a un codice di 500 risposta:

{ 
    "Message": "An error has occurred.", 
    "ExceptionMessage": "Processing of the HTTP request resulted in an exception. Please see the HTTP response returned by the 'Response' property of this exception for details.", 
    "ExceptionType": "System.Web.Http.HttpResponseException", 
    "StackTrace": " at AccountCodeAssignmentService.Controllers.InvoicesController.<AssignAccountCodesToInvoiceById>d__0.MoveNext() in c:\\Projects\\AccountCodeAssignmentService\\Source\\AccountCodeAssignmentService\\Controllers\\InvoicesController.cs:line 38\r\n at Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.SerializeList(JsonWriter writer, IEnumerable values, JsonArrayContract contract, JsonProperty member, JsonContainerContract collectionContract, JsonProperty containerProperty)\r\n at Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.SerializeValue(JsonWriter writer, Object value, JsonContract valueContract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerProperty)\r\n at Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.Serialize(JsonWriter jsonWriter, Object value, Type objectType)\r\n at Newtonsoft.Json.JsonSerializer.SerializeInternal(JsonWriter jsonWriter, Object value, Type objectType)\r\n at System.Net.Http.Formatting.BaseJsonMediaTypeFormatter.WriteToStream(Type type, Object value, Stream writeStream, Encoding effectiveEncoding)\r\n at System.Net.Http.Formatting.JsonMediaTypeFormatter.WriteToStream(Type type, Object value, Stream writeStream, Encoding effectiveEncoding)\r\n at System.Net.Http.Formatting.BaseJsonMediaTypeFormatter.WriteToStream(Type type, Object value, Stream writeStream, HttpContent content)\r\n at System.Net.Http.Formatting.BaseJsonMediaTypeFormatter.WriteToStreamAsync(Type type, Object value, Stream writeStream, HttpContent content, TransportContext transportContext, CancellationToken cancellationToken)\r\n--- End of stack trace from previous location where exception was thrown ---\r\n at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)\r\n at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n at System.Web.Http.Owin.HttpMessageHandlerAdapter.<BufferResponseContentAsync>d__13.MoveNext()" 
} 

Tutte le idee su quello che stiamo facendo di sbagliato o è HttpResponseException non supportato quando usando Owin self-hosting?

Edit: Uno dei grandi vantaggi di utilizzare WebAPI per noi è la capacità di lavorare con e restituire i nostri tipi, quindi vorremmo evitare di dover cambiare il tipo di ritorno. Attualmente stiamo cedendo AccountCodeAssignment in modo che la modifica del tipo di reso non sia un'opzione.

risposta

3

non credo che il problema è in lancio HttpResponseException. Se si esamina la traccia dello stack che è stata inviata, il problema sembra essere nella chiamata a MoveNext(). Questa è una rappresentazione interna in C# delle dichiarazioni yield che hai.

Potrei sbagliarmi, ma il modo più semplice per verificare ciò è di inserire un punto di interruzione nella prima dichiarazione di rendimento e vedere se lo colpisce. La mia ipotesi è che lo farà, cioè non getterà un HttpResponseException. Inoltre, basta modificare temporaneamente il codice per lanciare sempre uno HttpResponseException e vedere come lo gestisce.

Attualmente sto lavorando a un progetto che è auto-ospitato usando OWIN e posso lanciare HttpResponseException s senza problemi.

Su una nota correlata, è possibile esaminare global exception handling. Ho trovato molto utile concentrare tutta la mia gestione delle eccezioni in un unico posto. Si noti che HttpResponseException è un caso speciale e non è gestito dal gestore di eccezioni globale.

+0

Sì, il problema sembra essere correlato a "rendimento". Se estraiamo le righe di rendimento in un metodo che restituisce IEnumberable e restituisci il risultato di tale metodo nell'azione, funziona! Quindi immagino che la causa sia stata trovata ma non vedo ancora perché questo potrebbe accadere !? Per riassumere, non cedere e utilizzare HttpResponseException nello stesso metodo! –

1

Non sicuro al 100%, ma che può happend perché la vostra azione di richiamo IEnumerable <>

Prova cambiarlo in IHttpActionResult

provare questo

[ResponseType(typeof(AccountCodeAssignment))] 
     public IHttpActionResult AssignAccountCodesToInvoiceById (int id) 
     { 

     var invoice = _invoiceRepository.Get(id); 

       if (invoice == null) { 

       return NotFound(); 
     } 



       return Ok(invoice); 
      } 
+0

Potrebbe funzionare ma vogliamo utilizzare e restituire i nostri tipi. Uno dei grandi vantaggi dell'utilizzo di WebApi per noi è la possibilità di farlo, quindi vorremmo evitare di dover cambiare il tipo di reso. Attualmente stiamo cedendo AccountCodeAssignment, quindi questo approccio non funziona per noi. –

+0

È possibile aggiungere l'attributo ResponseType, per cui test dovrebbe funzionare correttamente. – sylwester

+0

Bene, la chiave qui è che stiamo producendo più \t \t \t AccountCodeAssignment's (vedi l'esempio aggiornato) quindi se cambiamo il tipo di ritorno, il compilatore si lamenterà! L'attributo ResponseType non risolve questo problema e non me lo aspetterei. –

2

L'ho sperimentato mentre stavo usando il postino per testare l'API Web e il tipo di richiesta era impostato su testo normale anziché su applicazione/json.

Problemi correlati