gpt4 book ai didi

c# - 反序列化 mimekit.MimeMessage 对象

转载 作者:行者123 更新时间:2023-12-03 19:11:16 27 4
gpt4 key购买 nike

我在反序列化 mimeKit.mimeMessage 时遇到一些问题,我将其序列化为 JSON 字符串并存储在 redis 键值缓存中。

我能够使用 json.NET 或 Jil 成功地序列化和存储 mimeMessage,但是当我去反序列化时,抛出以下错误。

由 json.NET 抛出

Unable to find a constructor to use for type MimeKit.Header. A class should either have a default constructor, one constructor with arguments or a constructor marked with the JsonConstructor attribute. Path 'Headers[0].Offset', line 1, position 22.

我正在使用 StackExchange.Redis 方法 stringGet 来获取序列化对象,然后将 RedisValue 传递给 Json.Net;下面的代码片段:

RedisValue result = db.StringGet(key);

MimeMessage message = new MimeMessage();

message = JsonConvert.DeserializeObject<MimeMessage>(result);

据我所知,默认构造函数总是被创建,这让我有点难以理解,默认构造函数是否已被指定为私有(private),如果是,为什么?

我也检查了返回的JSON字符串的格式,是正确的。

感谢您的帮助。

最佳答案

首先,清理一下:

It is my understanding that a default constructor is always created, which makes this a little hard to get my head around, could the default constructor have been specified as private, and if so why?

那不是真的。当您定义一个没有 构造函数的类时,会为您生成一个默认的无参数构造函数。如果您提供构造函数,则不再生成此默认构造函数。换句话说,一个类可能没有默认构造函数。


考虑到这一点,MimeKit.Header 类提供了 6 个构造函数,其中没有一个不带参数。因此,JSON.NET 不知道如何实例化这个类,这就是出现异常的原因。

由于您无法控制 MimeKit.Header 类,让 JSON.NET 知道如何构造 Header 实例的一种方法是使用自定义转换器:

public class MimeHeaderConverter : JsonConverter
{
public override object ReadJson(
JsonReader reader,
Type objectType,
object existingValue,
JsonSerializer serializer)
{
JObject obj = serializer.Deserialize<JObject>(reader);

HeaderId headerId = obj["Id"].ToObject<HeaderId>();

Header header = new Header(headerId, obj["Value"].ToObject<string>());

return header;
}

public override void WriteJson(
JsonWriter writer,
object value,
JsonSerializer serializer)
{
throw new NotImplementedException();
}

public override bool CanConvert(Type t)
{
return typeof(Header).IsAssignableFrom(t);
}

public override bool CanRead { get { return true; } }

public override bool CanWrite { get { return false; } }
}

在这里,我们首先将 Header 类反序列化为 JObject。然后,我们从 JObject 中选取 HeaderIdValue 以创建 Header 实例。

这里要注意:我对这个库了解不多。这可能不是实例化 Header 的最佳方式,而且我可能会不小心丢弃一些信息。我只做了一些非常基本的测试。

一旦解决了这个问题,您就会遇到另一个与不接受 null 值的属性 setter 有关的问题。

具体来说,ResentMessageIdMimeVersion 属性在 setter 中有逻辑,如果您提供 null。这是一个问题,因为当 MimeMessage 被实例化时,这些值可以为空。

一个解决方法是创建一个排除这些属性的 ContractResolver:

public class MimeMessageContractResolver : DefaultContractResolver
{
private static HashSet<string> excludedMembers = new HashSet<string>
{
"ResentMessageId",
"MimeVersion"
};

protected override List<MemberInfo> GetSerializableMembers(Type objectType)
{
var baseMembers = base.GetSerializableMembers(objectType);

if (typeof(MimeMessage).IsAssignableFrom(objectType))
{
baseMembers.RemoveAll(m => excludedMembers.Contains(m.Name));
}

return baseMembers;
}
}

这样,我们就不会意外地将 null 传递给其中一个属性的 setter 。

这里还有一个注意事项:我注意到即使我忽略了 MimeVersionResentMessageId 如果 header 包含MimeVersion 和/或 ResentMessageId header 。我猜这是在某处嵌入到 MimeMessage 中,但同样,我对这个库并不完全熟悉。

所以要使用上面的类(仅在反序列化时),您需要这样做:

string someJsonString = "{ ... }";

MimeMessage deserialized = JsonConvert.DeserializeObject<MimeMessage>(
someJsonString, new JsonSerializerSettings
{
ContractResolver = new MimeMessageContractResolver(),
Converters = new JsonConverter[]
{
new MimeHeaderConverter()
}
});

通过一些基本测试,这似乎工作正常。您最终可能会在实际使用中遇到更多问题,因此无法保证。

希望这至少能让您入门。

关于c# - 反序列化 mimekit.MimeMessage 对象,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30712228/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com