提问人:Szyszka947 提问时间:9/18/2023 更新时间:9/24/2023 访问量:221
如何在不引发异常的情况下安全地反序列化 MessagePack 消息?
How to safely deserialize MessagePack messages without throwing exceptions?
问:
这是我的DTO:
public class InvocationMessage
{
public string MethodName { get; set; }
public object?[]? Args { get; set; }
}
最初我使用MessagePackSerializer.Serialize(Msg, ContractlessStandardResolver.Options);
然后,在反序列化时,我想从具体类型转换为具体类型。如果没有自定义格式化程序,这似乎是不可能的。所以我写了一个:object
Args
public InvocationMessage Deserialize(ref MessagePackReader reader, MessagePackSerializerOptions options)
{
var result = new InvocationMessage
{
MethodName = reader.ReadString()
};
// Hardcoded for testing purpose
var argTypes = new Type[] { typeof(SomeType) };
if (reader.TryReadArrayHeader(out int count))
{
result.Args = new object?[count];
for (int i = 0; i < argTypes.Length; i++)
{
result.Args[i] = MessagePackSerializer.Deserialize(argTypes[i], ref reader,
ContractlessStandardResolver.Options.WithSecurity(MessagePackSecurity.UntrustedData));
}
}
return result;
}
public void Serialize(ref MessagePackWriter writer, InvocationMessage value, MessagePackSerializerOptions options)
{
var methodName = Encoding.UTF8.GetBytes(value.MethodName);
writer.WriteString(methodName);
if (value.Args is not null && value.Args.Length > 0)
{
writer.WriteArrayHeader(value.Args.Length);
foreach (var arg in value.Args)
{
MessagePackSerializer.Serialize(ref writer, arg, ContractlessStandardResolver.Options);
}
}
}
不幸的是,当我尝试反序列化时,总是抛出异常,例如:
var msg = new InvocationMessage
{
MethodName = "sometestname",
Args = new object?[]
{
new
{
Test = 3
},
new
{
ReceiverId = "12ds",
Content = "s",
},
new
{
Test2 = 5
},
}
};
这是因为我想将一些未知类型反序列化到我的 ,或者因为我想要属性并得到 .在很多情况下,它都会抛出。SomeType
SomeType
string
ReceiverId
int
但我需要避免抛出,因为这对我的应用程序来说是一个很大的性能问题。没有类似方法的东西,所以我不知道我能做什么。TryDeserialize
答:
2赞
Freeman
9/24/2023
#1
我认为最好编辑您的反序列化代码以使用处理未知类型或类型不匹配的自定义格式化程序,因此首先为您的定义自定义格式化程序InvocationMessage
public class InvocationMessageFormatter : IMessagePackFormatter<InvocationMessage>
{
public InvocationMessage Deserialize(ref MessagePackReader reader, MessagePackSerializerOptions options)
{
var result = new InvocationMessage
{
MethodName = reader.ReadString()
};
if (reader.TryReadArrayHeader(out int count))
{
result.Args = new object?[count];
for (int i = 0; i < count; i++)
{
result.Args[i] = DeserializeObject(ref reader, options);
}
}
return result;
}
public void Serialize(ref MessagePackWriter writer, InvocationMessage value, MessagePackSerializerOptions options)
{
writer.WriteString(value.MethodName);
if (value.Args is not null && value.Args.Length > 0)
{
writer.WriteArrayHeader(value.Args.Length);
foreach (var arg in value.Args)
{
SerializeObject(ref writer, arg, options);
}
}
}
private object? DeserializeObject(ref MessagePackReader reader, MessagePackSerializerOptions options)
{
/* you can return null or a default value for unknown types,
or convert the object to the expected type if possible.
I'll simply return null for unknown types */
return null;
}
private void SerializeObject(ref MessagePackWriter writer, object? value, MessagePackSerializerOptions options)
{
//you can throw an exception or convert the object to a compatible type,for example, I'll do nothing when serializing unknown types
}
}
现在,您可以轻松地在序列化/反序列化代码中注册自定义格式化程序
var options = MessagePackSerializerOptions.Standard.WithResolver(ContractlessStandardResolver.Options);
options = options.WithFormatter<InvocationMessage>(new InvocationMessageFormatter());
//serialize
var serializedBytes = MessagePackSerializer.Serialize(msg, options);
//deserialize
var deserializedMsg = MessagePackSerializer.Deserialize<InvocationMessage>(serializedBytes, options);
评论
0赞
Szyszka947
9/24/2023
但是,如何确保某些字节表示有效类型呢?我知道,我可以捕捉到异常,但我必须避免它们
0赞
Freeman
9/24/2023
许多方法,例如,在反序列化之前,可以对序列化数据执行一些基本检查,以确保其有效。例如,可以检查字节数组是否为 null 或为空,或者它是否具有最小长度,或者在反序列化时,从字节中读取类型标识符并检查它是否与预期类型匹配。如果它们不匹配,您可以相应地处理错误,依此类推!
0赞
Szyszka947
9/26/2023
但这不会有效,因为在我的情况下,我可能需要使用反射:/它扼杀了 MessagePack 的优势(性能)。
评论
SomeType
Args
MessagePackSerializer
Args
MessagePackObject
Key
Args
object?[]
i
Args