本文介绍了如何引发反序列化异常?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用 JsonConvert.SerializeObject 在服务器上序列化 Exception ,然后编码为 byte [] 并在客户端中反序列化使用 JsonConvert.DeserializeObject .到目前为止一切正常...问题是当我抛出 Exception 被替换的堆栈跟踪时,让我演示一下:

  public void HandleException(RpcException exp){//获取异常字节[]字符串exceptionString = exp.Trailer.GetBytes("exception-bin");//反序列化异常异常exception = JsonConvert.DeserializeObject< Exception>(exceptionString,newJsonSerializerSettings {TypeNameHandling = TypeNameHandling.All});//记录异常:stacktrace是正确的.例如:在ServerMethod()Console.WriteLine(exception);//抛出相同的异常:更改了堆栈跟踪.例如:在HandleException()ExceptionDispatchInfo.Capture(exception).Throw();} 
解决方案

如果反序列化 Exception 并设置 JsonSerializerSettings.Context = new StreamingContext(StreamingContextStates.CrossAppDomain) ,然后反序列化的堆栈跟踪字符串将被添加到显示的="https://docs.microsoft.com/zh-cn/dotnet/api/system.exception.stacktrace?view=net-5.0" rel ="nofollow noreferrer"> StackTrace 即使在引发异常之后:

  var设置=新的JsonSerializerSettings{TypeNameHandling = TypeNameHandling.All,上下文=新的StreamingContext(StreamingContextStates.CrossAppDomain),};var exception = JsonConvert.DeserializeObject< Exception>(exceptionString,设置); 

注意:

  • 之所以可行,是因为在用于 Exception ,反序列化的堆栈跟踪字符串将保存到 _remoteStackTraceString 中,该前缀随后会添加到常规堆栈跟踪中:

  • 虽然 Exception 的序列化流确实包含堆栈跟踪字符串,但它不会尝试捕获 私有对象_stackTrace ,运行时使用它来识别在执行程序集中的哪个位置抛出了异常.这似乎就是为什么 ExceptionDispatchInfo > 在引发异常时无法复制和使用此信息.因此,似乎不可能抛出反序列化的异常并恢复其真实"异常.序列化流中的堆栈跟踪.

  • 为了使Json.NET使用其流构造函数反序列化类型(从而根据需要设置远程跟踪字符串),必须使用 [Serializable] 并实现 ISerializable . System.Exception 满足这两个要求,但是某些 Exception 的派生类并不总是添加 [Serializable] 属性.如果您的特定序列化异常缺少该属性,请参见 在Newtonsoft.Json 中反序列化自定义异常./p>

  • 使用 TypeNameHandling.All 反序列化异常是不安全的,并且在从不受信任的来源反序列化时可能导致注入攻击类型.请参阅: 由于Json.Net TypeNameHandling auto,外部JSON容易受到攻击? 其答案专门讨论了反序列化例外.

演示小提琴此处.

I'm serializing a Exception at the server with JsonConvert.SerializeObject and then encoding to a byte[] and deserializing in the client using JsonConvert.DeserializeObject. Everything works fine so far... The problem is when I throw the Exception the stacktrace being replaced, let me demostrate:

public void HandleException(RpcException exp)
{
    // Get the exception byte[]
    string exceptionString = exp.Trailer.GetBytes("exception-bin");

    // Deserialize the exception
    Exception exception = JsonConvert.DeserializeObject<Exception>(exceptionString, new
    JsonSerializerSettings { TypeNameHandling = TypeNameHandling.All });

    // Log the Exception: The stacktrace is correct. Ex.: at ServerMethod()
    Console.WriteLine(exception);

    // Throw the same Exception: The stacktrace is changed. Ex.: at HandleException()
    ExceptionDispatchInfo.Capture(exception).Throw();
}
解决方案

If you deserialize an Exception and set JsonSerializerSettings.Context = new StreamingContext(StreamingContextStates.CrossAppDomain) then the deserialized stack trace string will get prepended to the displayed StackTrace even after the exception is thrown:

var settings = new JsonSerializerSettings
{
    TypeNameHandling = TypeNameHandling.All,
    Context = new StreamingContext(StreamingContextStates.CrossAppDomain),
};
var exception = JsonConvert.DeserializeObject<Exception>(exceptionString, settings);

Notes:

  • This works because, in the streaming constructor for Exception, the deserialized stack trace string is saved into a _remoteStackTraceString which is later prepended to the regular stack trace:

  • While the serialization stream for Exception does contain the stack trace string, it does not attempt to capture the private Object _stackTrace which is used by the runtime to identify where in the executing assembly the exception was thrown. This would seem to be why ExceptionDispatchInfo is unable to copy and use this information when throwing the exception. Thus it seems to be impossible to throw a deserialized exception and restore its "real" stack trace from the serialization stream.

  • In order Json.NET to deserialize a type using its streaming constructor (and thus set the remote trace string as required), the type must be marked with [Serializable] and implement ISerializable. System.Exception meets both requirements, but some derived classes of Exception do not always add the [Serializable] attribute. If your specific serialized exception lacks the attribute, see Deserializing custom exceptions in Newtonsoft.Json.

  • Deserializing an exception with TypeNameHandling.All is insecure and may lead to injection of attack types when deserializing from untrusted sources. See: External json vulnerable because of Json.Net TypeNameHandling auto? whose answer specifically discusses deserialization of exceptions.

Demo fiddle here.

这篇关于如何引发反序列化异常?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-24 15:15