【问题标题】:Serializing an Exception Return a Very Large JSON序列化异常返回一个非常大的 JSON
【发布时间】:2018-10-03 18:17:59
【问题描述】:

我正在将应用程序从完整框架迁移到网络核心。 我正在努力让 API 的异常管理器开始工作。

我目前正在使用基于属性的解决方案。

我有这门课

public class ApiExceptionFilterAttribute : ExceptionFilterAttribute
{
    public override async void OnException(ExceptionContext context)
    {
        context.HttpContext.Response.StatusCode = (int)HttpStatusCode.InternalServerError;
        var ex = context.Exception;
        if (ex == null) return;

        context.HttpContext.Response.ContentType = "application/json";

        using (var writer = new StreamWriter(context.HttpContext.Response.Body))
        {
            var js = new JsonSerializer();
            js.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
            js.Serialize(writer, ex);
            await writer.FlushAsync().ConfigureAwait(false);
        }
    }
}

我在所需的控制器上使用相应的属性。 [ApiExceptionFilter]

问题是,当我捕获异常并将其作为 JSON 字符串抛出给客户端时。我下载了 27mb,因为它正在序列化 TargetSite 并且在其中序列化了 DefinedTypes,它是程序集和类型的列表。

有人知道如何序列化异常以避免这些属性吗?

这里是一个例外的例子:

{
Id: null,
Message: "Hubo errores en la validación de los parámetros de la operación.",
Data: { },
InnerException: {
Detail: {
Details: [
{
Key: "Cuit",
Message: "The field Cuit must match the regular expression '^[0-9]{11}$'.",
ParameterName: "request"
}
]
},
Action: null,
Code: {
IsPredefinedFault: true,
IsSenderFault: true,
IsReceiverFault: false,
Namespace: "http://schemas.xmlsoap.org/soap/envelope/",
Name: "Client",
SubCode: null
},
Message: "Hubo errores en la validación de los parámetros de la operación.",
Reason: {
Translations: [
{
XmlLang: "en-US",
Text: "Hubo errores en la validación de los parámetros de la operación."
}
]
},
Data: { },
InnerException: null,
TargetSite: {
Name: "HandleReply",
DeclaringType: "System.ServiceModel.Channels.ServiceChannel, System.Private.ServiceModel, Version=4.5.0.3, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a",
ReflectedType: "System.ServiceModel.Channels.ServiceChannel, System.Private.ServiceModel, Version=4.5.0.3, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a",
MemberType: 8,
MetadataToken: 100671507,
Module: {
MDStreamVersion: 131072,
FullyQualifiedName: "C:\Users\rotha\.nuget\packages\system.private.servicemodel\4.5.3\runtimes\win\lib\netstandard2.0\System.Private.ServiceModel.dll",
ModuleVersionId: "c5851175-5eba-412a-8f03-6cd647a2a897",
MetadataToken: 1,
ScopeName: "System.Private.ServiceModel.dll",
Name: "System.Private.ServiceModel.dll",
Assembly: {
CodeBase: "file:///C:/Users/xxx/.nuget/packages/system.private.servicemodel/4.5.3/runtimes/win/lib/netstandard2.0/System.Private.ServiceModel.dll",
FullName: "System.Private.ServiceModel, Version=4.5.0.3, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a",
EntryPoint: null,
DefinedTypes: [
"FxResources.System.Private.ServiceModel.SR, System.Private.ServiceModel, Version=4.5.0.3, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a",
"System.NotImplemented, System.Private.ServiceModel, Version=4.5.0.3, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a",
"System.__HResults, System.Private.ServiceModel, Version=4.5.0.3, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a",
"System.FxTrace, System.Private.ServiceModel, Version=4.5.0.3, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a",
"System.SR, System.Private.ServiceModel, Version=4.5.0.3, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a",
"System.Xml.XmlBinaryNodeType, System.Private.ServiceModel, Version=4.5.0.3, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a",
"System.Collections.Generic.KeyedByTypeCollection`1, System.Private.ServiceModel, Version=4.5.0.3, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a",
"System.Collections.Generic.SynchronizedCollection`1, System.Private.ServiceModel, Version=4.5.0.3, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a",
"System.Collections.Generic.SynchronizedKeyedCollection`2, System.Private.ServiceModel, Version=4.5.0.3, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a",
"System.Collections.Generic.SynchronizedReadOnlyCollection`1, System.Private.ServiceModel, Version=4.5.0.3, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a",
..........

这个定义类型的列表,有大约一百万个项目...... :(

【问题讨论】:

  • 这是因为您正在将响应正文写入流。而只是传递有关异常的信息。
  • 对不起,我没有关注你...
  • 我需要将异常作为 json 字符串发送,我想我没有解释。
  • 为什么要在响应中写入异常?似乎这会将详细信息泄露给消费应用程序,它不需要知道 API 如何 失败。只是它失败了。似乎您应该记录错误,然后为未处理的异常编写通用的“出现问题”响应。
  • 是的,你说得有道理。

标签: c# asp.net-core .net-core json.net


【解决方案1】:

不需要用任何writer写,直接用context.Result

public class ApiExceptionFilterAttribute : ExceptionFilterAttribute
{
    public override void OnException(ExceptionContext context)
    {
        context.HttpContext.Response.StatusCode = (int)HttpStatusCode.InternalServerError;
        var ex = context.Exception;
        if (ex == null) return;

        context.Result = new JsonResult(ex);
    }
}

【讨论】:

  • 是的,谢谢你的例子。但不幸的是,我仍然收到 28mb 的响应... :(
  • @Rothariger,好吧,这意味着您的序列化异常大小为 28mb。您是否在某处配置了序列化程序?
【解决方案2】:

这应该在 Json.NET 的Release 12.0.1 中修复:

更改 - 在序列化没有 SerializableAttribute 的异常时排除 TargetSite

在 2018 年 10 月 27 日提交 Exclude TargetSite from non-serializable Exception serialization (#1897) 中进行了修复。

问题好像已经在Json.NET 11.0 Release 1中引入了:

更改 - 实现 ISerializable 但没有 [SerializableAttribute] 的类型不使用 ISerializable 进行序列化

有关最初对 11.0.1 进行更改的原因的讨论,请参阅 this answerDeserializing custom exceptions in Newtonsoft.Json

【讨论】:

    猜你喜欢
    • 2023-02-18
    • 2010-10-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-01-09
    • 1970-01-01
    • 2012-04-14
    • 2014-01-21
    相关资源
    最近更新 更多