【问题标题】:Throwing HttpResponseException from WebApi controller when using Owin self host使用 Owin 自主机时从 WebApi 控制器抛出 HttpResponseException
【发布时间】:2014-08-24 06:13:24
【问题描述】:

我们正在构建一个使用 Owin 托管的 WebApi。之前我们在控制器操作中使用 HttpResponseException 来返回 404 状态码等,并且运行良好。

但是,当我们开始使用 Owin(自托管)时,我们遇到了这种方法的问题,导致 HttpResponseException 被序列化为 json/xml 并且状态代码从 404 更改为 500(内部服务器错误)。这是我们的代码:

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

这是我们得到的响应以及 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()"
}

关于我们做错了什么或使用 Owin 自托管时不支持 HttpResponseException 的任何想法?

编辑: 为我们使用 WebApi 的一大优势是能够使用和返回我们自己的类型,因此我们希望避免更改返回类型。我们目前正在生成 AccountCodeAssignment,因此无法更改返回类型。

【问题讨论】:

    标签: c# asp.net-web-api owin


    【解决方案1】:

    我在使用 postman 测试 web api 并且请求类型设置为纯文本而不是 application/json 时遇到了这种情况。

    【讨论】:

    • 3 年后,您的回答为我指明了正确的方向。由于我忘记删除另一个请求的标头,我遇到了同样的问题,这导致了错误。谢谢你:)
    【解决方案2】:

    我认为问题不在于抛出 HttpResponseException。如果您查看您发布的堆栈跟踪,则问题似乎出在对MoveNext() 的调用中。这是您拥有的 yield 语句的内部 C# 表示形式。

    我可能是错的,但验证这一点的最简单方法是在第一个 yield 语句上放置一个断点,看看它是否命中它。我的猜测是它会,即它不会抛出HttpResponseException。此外,只需暂时更改您的代码以始终抛出 HttpResponseException 并查看它是如何处理它的。

    我目前正在开发一个使用 OWIN 自托管的项目,我可以毫无问题地抛出 HttpResponseExceptions。

    在相关说明中,您可能需要调查global exception handling。我发现将所有异常处理集中在一个地方非常有用。请注意,HttpResponseException 是一种特殊情况,不由全局异常处理程序处理。

    【讨论】:

    • 是的,这个问题似乎与“产量”有关。如果我们将产生的行提取到返回 IEnumberable 的方法中,并在操作中返回该方法的结果,它就可以工作!所以我想原因已经找到了,但我仍然不明白为什么会发生这种情况!?总而言之,不要在同一个方法中产生和使用 HttpResponseException!
    【解决方案3】:

    对我来说,我的 api 标头中缺少内容类型。将内容类型添加为 application/json 后,为我解决了这个问题。可能会帮助其他人。

    【讨论】:

      【解决方案4】:

      您可以在OnException() 中的异常上放置断点并查看context.Exception.Response,并查看“原因短语”以获取解释。

      您也可以通过代码访问它:

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

      对我来说是

      不支持的媒体类型

      当您进行文本请求时可能会发生其他人已经提到的情况,因为默认情况下不会处理文本请求。如果您确实想允许文本,请查看: how to post plain text to ASP.NET Web API endpoint?

      【讨论】:

        【解决方案5】:

        不是 100% 确定,但这可能是因为您的操作返回 IEnumerable

        试试改成IHttpActionResult

        试试这个

          [ResponseType(typeof(AccountCodeAssignment))]
                 public IHttpActionResult AssignAccountCodesToInvoiceById (int id)
                {
        
                 var invoice = _invoiceRepository.Get(id);
        
                        if (invoice == null) {
        
                        return NotFound();
                 }
        
        
        
                       return Ok(invoice);
                    }
        

        【讨论】:

        • 这可能有效,但我们想使用并返回我们自己的类型。对我们来说使用 WebApi 的一大优势是能够做到这一点,因此我们希望避免更改返回类型。我们目前正在生成 AccountCodeAssignment,因此这种方法对我们不起作用。
        • 您可以添加 ResponseType 属性,请测试是否适合您。
        • 好吧,这里的关键是我们产生了多个 AccountCodeAssignment(参见更新的示例),所以如果我们更改返回类型,编译器会报错! ResponseType 属性不能解决这个问题,我不希望它。
        猜你喜欢
        • 2018-11-22
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多