Throwing HttpResponseException from WebApi controller when using Owin self host

46,485

Solution 1

I don't think the problem is in throwing HttpResponseException. If you look at the stack trace you posted, the problem appears to be in the call to MoveNext(). This is an internal C# representation of the yield statements you have.

I could be wrong, but the easiest way to verify this is to put a breakpoint on the first yield statement and see if it hits it. My guess is that it will, i.e. it won't throw a HttpResponseException. Also, just change your code temporarily to always throw an HttpResponseException and see how it handles it.

I'm currently working on a project that's self-hosted using OWIN and I can throw HttpResponseExceptions without any issues.

On a related note, you may want to investigate global exception handling. I found it very useful to concentrate all my exception handling in one place. Note that HttpResponseException is a special case and is not handled by the global exception handler.

Solution 2

I experienced this while I was using postman to test the web api and the request type was set to plain text instead of application/json.

Solution 3

You can put a breakpoint on the exception in OnException() and view the context.Exception.Response, and see the "Reason Phrase" for an explanation.

You can also do this to access it via code:

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

For me it was

Unsupported Media Type

Which other people have already mentioned can happen when you do a text request, because text requests are not handled by default. If you do want to allow text, maybe look at: how to post plain text to ASP.NET Web API endpoint?

Solution 4

For me, I was missing content-type in my api header. After adding the content-type as application/json resolved this issue for me. Might help others with this.

Solution 5

Not 100% sure but that may happend because your action returning IEnumerable<>

Try change it to IHttpActionResult

try this

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

         var invoice = _invoiceRepository.Get(id);

                if (invoice == null) {

                return NotFound();
         }



               return Ok(invoice);
            }
Share:
46,485
Kristoffer Ahl
Author by

Kristoffer Ahl

Updated on June 28, 2020

Comments

  • Kristoffer Ahl
    Kristoffer Ahl almost 4 years

    We are building a WebApi that we're hosting using Owin. Previously we've used HttpResponseException for returning 404 status codes etc. in our controller actions and it's been working well.

    However, when we started working with Owin (self hosted) we're experiencing an issue with this approach resulting in the HttpResponseException being serialized to json/xml and the status code to change from 404 to 500 (Internal Server Error). Here's the code we have:

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

    and this is the response we get back along with a 500 response code:

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

    Any ideas on what we're doing wrong or is HttpResponseException not supported when using Owin self hosting?

    Edit: One of the big advantages of using WebApi for us is the ability to work with and return our own types, so we would like to avoid having to change the return type. We're currently yielding AccountCodeAssignment's so changing the return type is not an option.

  • Kristoffer Ahl
    Kristoffer Ahl almost 10 years
    That may work but we want to use and return our own types. One of the big advantages of using WebApi for us is the ability to do this, so we would like to avoid having to change the return type. We're currently yielding AccountCodeAssignment's so this approach does not work for us.
  • sylwester
    sylwester almost 10 years
    You can add ResponseType attribute please test should works for you.
  • Kristoffer Ahl
    Kristoffer Ahl almost 10 years
    Well, the key here is that we are yielding multiple AccountCodeAssignment's (see the updated example) so if we change the return type, the compiler will complain! ResponseType attribute does not fix this and I would not expect it to.
  • Kristoffer Ahl
    Kristoffer Ahl almost 10 years
    Yes, the issue seems to be related to "yield". If we extract the yielding rows into a method returning IEnumberable<AccountCodeAssignment> and return the result of that method in the action, it works! So I guess the cause has been found but I still don't see why this would happen!? To summarize, don't yield and use HttpResponseException in the same method!
  • Ibrahim Mezouar
    Ibrahim Mezouar almost 4 years
    3 years later, your answer pointed me in the right direction. I was having the same issue due to a header from another request I forgot to remove, which was causing the error. Thank you :)