WebAPI 如何在 (.NET) 客户端反序列化异常

WebAPI how do I deserialize exceptions on the (.NET) client side

我有一个 webAPI 2 控制器,目前它正在抛出异常,并且正在通过响应消息将其发送回客户端。 500 内部服务器错误,它自身的异常被序列化,我可以在 fiddler 中看到它的 json 表示。 (json 粘贴在下方)

我一直在尝试找到一种方法将此异常反序列化回 .NET 异常对象,但不断收到错误消息:

"Member 'ClassName' was not found."

目前在我的客户端中,我正在尝试通过以下代码反序列化异常。

if (apiResponse.ResponseCode.Equals(500)) // Unhandled exception on server
{
    var exceptionObject = await response.Content.ReadAsAsync<Exception>();
}

如何在客户端应用程序中正确反序列化此异常对象?理想情况下,我应该能够取回原始 System.InvalidOperationException` 对象。

下面是我在 fiddler 中捕获的试图反序列化的响应:

HTTP/1.1 500 Internal Server Error Cache-Control: no-cache Pragma: no-cache Content-Type: application/json; charset=utf-8 Expires: -1 Server: Microsoft-IIS/10.0 X-AspNet-Version: 4.0.30319 X-Powered-By: ASP.NET Date: Wed, 30 Sep 2015 13:43:42 GMT Content-Length: 1556

{"Message":"An error has occurred.","ExceptionMessage":"UrlHelper.Link must not return null.","ExceptionType":"System.InvalidOperationException","StackTrace":" at System.Web.Http.Results.CreatedAtRouteNegotiatedContentResult1.Execute()\r\n at System.Web.Http.Results.CreatedAtRouteNegotiatedContentResult1.ExecuteAsync(CancellationToken cancellationToken)\r\n at System.Web.Http.Controllers.ApiControllerActionInvoker.d__0.MoveNext()\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.Controllers.ActionFilterResult.d__2.MoveNext()\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.Filters.AuthorizationFilterAttribute.d__2.MoveNext()\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.Dispatcher.HttpControllerDispatcher.d__1.MoveNext()"}

感谢 Serg Rogovtsev 的评论,我现在知道您拥有的不是 Exception,而是 HttpError。因此,您必须这样处理它:

var exceptionObject = await response.Content.ReadAsAsync<System.Web.Http.HttpError>();

不过,我仍然不认为这是个好主意。 500 状态代码通常意味着出现意外错误并且服务器端没有任何东西可以捕获它。如果您可以控制服务器,我强烈建议您在那里处理此类错误。 无论如何,客户端对此无能为力,所以它所需要的只是某种错误通知。

旧答案(在评论 HttpError 之前):

序列化的 Exception 看起来像这样:

{
    "ClassName":"System.Exception",
    "Message":"some exception",
    "Data":null,
    "InnerException":null,
    "HelpURL":null,
    "StackTraceString":null,
    "RemoteStackTraceString":null,
    "RemoteStackIndex":0,
    "ExceptionMethod":null,
    "HResult":-2146233088,
    "Source":null,
    "WatsonBuckets":null
}

您得到的只是一条格式化的错误消息,其中包含有关异常的信息。

顺便说一句:我不会尝试在客户端捕获服务器端异常。您需要处理服务器上的错误并向客户端提供足够的信息以告知用户发生了什么。

我找到了获得我想要的 json 异常的好方法。我在查看 ASPNET git 存储库上的示例时得到了这个。

在 ASPNET Startup.cs 配置方法中添加以下内容(仅适用于开发环境,因为如其他答案所述,500 可能对客户端没有用)

public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
    if (env.IsDevelopment())
    {
        app.Use(async (context, next) =>
        {
             try
             {
                  await next();
             }
             catch (Exception ex)
             {
                  if (context.Response.HasStarted)
                  {
                      throw;
                  }
                  context.Response.StatusCode = 500;
                  await context.Response.WriteJsonExcpetionAsync(ex);
              }
        });
    }

    // Other config logic...
}