web-dev-qa-db-fra.com

Lancer HttpResponseException à partir du contrôleur WebApi lors de l'utilisation de l'auto-hôte Owin

Nous construisons un WebApi que nous hébergeons en utilisant Owin. Auparavant, nous avions utilisé HttpResponseException pour renvoyer 404 codes d'état, etc. dans nos actions de contrôleur et cela fonctionnait bien.

Cependant, lorsque nous avons commencé à travailler avec Owin (auto-hébergé), nous rencontrons un problème avec cette approche, ce qui entraîne la sérialisation de HttpResponseException en json/xml et le code d'état passe de 404 à 500 (erreur de serveur interne). Voici le code que nous avons:

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

et voici la réponse que nous obtenons avec un code de réponse 500:

{
    "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()"
}

Avez-vous des idées sur ce que nous faisons de mal ou HttpResponseException n'est-il pas pris en charge lors de l'utilisation de l'auto-hébergement Owin?

Edit: L'un des grands avantages de l'utilisation de WebApi pour nous est la possibilité de travailler avec et de renvoyer nos propres types, donc nous aimerions éviter d'avoir à changer le type de retour. Nous produisons actuellement des AccountCodeAssignment, donc changer le type de retour n'est pas une option.

12
Kristoffer Ahl

Je ne pense pas que le problème soit de lancer HttpResponseException. Si vous regardez la trace de pile que vous avez publiée, le problème semble être dans l'appel à MoveNext(). Il s'agit d'une représentation C # interne des instructions yield dont vous disposez.

Je peux me tromper, mais le moyen le plus simple de vérifier cela est de mettre un point d'arrêt sur la première déclaration de rendement et de voir s'il la frappe. Je suppose que c'est le cas, c'est-à-dire qu'il ne lancera pas un HttpResponseException. De plus, changez simplement votre code temporairement pour toujours jeter un HttpResponseException et voyez comment il le gère.

Je travaille actuellement sur un projet qui est auto-hébergé en utilisant OWIN et je peux lancer HttpResponseExceptions sans aucun problème.

Sur une note connexe, vous voudrez peut-être enquêter gestion des exceptions globales . J'ai trouvé très utile de concentrer toutes mes manipulations d'exception en un seul endroit. Notez que HttpResponseException est un cas spécial et n'est pas géré par le gestionnaire d'exceptions global.

4
djikay

J'ai vécu cela pendant que j'utilisais postman pour tester l'API Web et le type de demande a été défini en texte brut au lieu de application/json.

8
dhysong

Pour moi, il me manquait le type de contenu dans mon en-tête api. Après avoir ajouté le type de contenu en tant qu'application/json, j'ai résolu ce problème. Pourrait aider les autres avec cela.

2
briefcasejoe

Pas sûr à 100% mais cela peut arriver parce que votre action renvoyant IEnumerable <>

Essayez de le changer en IHttpActionResult

essaye ça

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

         var invoice = _invoiceRepository.Get(id);

                if (invoice == null) {

                return NotFound();
         }



               return Ok(invoice);
            }
1
sylwester

Vous pouvez placer un point d'arrêt sur l'exception dans OnException() et afficher le contexte . Exception.Response , et voir la "Phrase de raison" pour une explication.

Vous pouvez également le faire pour y accéder via le code:

((System.Web.Http.HttpResponseException)context.Exception).Response.ReasonPhrase

Pour moi c'était

Type de support non pris en charge

Les autres personnes déjà mentionnées peuvent se produire lorsque vous effectuez une demande de texte, car les demandes de texte ne sont pas traitées par défaut. Si vous souhaitez autoriser le texte, regardez peut-être: comment publier du texte brut sur le point de terminaison de l'API Web ASP.NET?

0
Andrew