【问题标题】:WebAPI how do I deserialize exceptions on the (.NET) client sideWebAPI如何在(.NET)客户端反序列化异常
【发布时间】:2015-12-28 08:40:39
【问题描述】:

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

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

“未找到成员 'ClassName'。”

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

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

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

下面是我试图反序列化的响应,如在提琴手中捕获的那样:

HTTP/1.1 500 内部服务器错误 缓存控制:无缓存 Pragma:无缓存 内容类型:应用程序/json;字符集=utf-8 过期:-1 服务器:Microsoft-IIS/10.0 X-AspNet-版本:4.0.30319 X-Powered-By: ASP.NET 日期:格林威治标准时间 2015 年 9 月 30 日星期三 13:43:42 内容长度:1556

{"Message":"发生错误。","ExceptionMessage":"UrlHelper.Link 不得返回 null。","ExceptionType":"System.InvalidOperationException","StackTrace":" 在 System.Web .Http.Results.CreatedAtRouteNegotiatedContentResult1.Execute()\r\n at System.Web.Http.Results.CreatedAtRouteNegotiatedContentResult1.ExecuteAsync(CancellationToken cancelToken)\r\n at System.Web.Http.Controllers.ApiControllerActionInvoker.d__0.MoveNext()\r\n--- 来自先前位置的堆栈跟踪结束抛出异常的位置 ---\r\n System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)\r\n System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n System. Web.Http.Controllers.ActionFilterResult.d__2.MoveNext()\r\n--- 从先前引发异常的位置结束堆栈跟踪 ---\r\n 在 System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task任务)\r\n 在 System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(任务任务)\r\n 在 System.Web.Ht tp.Filters.AuthorizationFilterAttribute.d__2.MoveNext()\r\n--- 从先前引发异常的位置结束堆栈跟踪---\r\n 在 System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(任务任务) \r\n 在 System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(任务任务)\r\n 在 System.Web.Http.Dispatcher.HttpControllerDispatcher.d__1.MoveNext()"}

【问题讨论】:

  • 你为什么想要那个?这样您就可以将您的实现与服务器紧密耦合。

标签: c# json asp.net-web-api asp.net-web-api2


【解决方案1】:

感谢 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
}

您所拥有的只是一个包含异常信息的格式化错误消息。

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

【讨论】:

  • 是的,WebAPI 将异常包装在 HttpError 中。
  • @SergRogovtsev 啊,很高兴知道。所以约翰可以将其反序列化为HttpError
  • 是的,考虑到这一点,我也认为这是一个坏主意。我现在只是将内容作为字符串读取并包装在客户端异常对象中。
【解决方案2】:

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

在 ASPNET Startup.cs Configure 方法中添加以下内容(仅适用于开发环境,因为如其他答案中所述,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...
}

【讨论】:

    猜你喜欢
    • 2019-10-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-09-20
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多