反序列化 mimekit.MimeMessage 对象
Deserialising mimekit.MimeMessage Object
我在反序列化 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);
据我所知,默认构造函数总是被创建,这让我有点难以理解,默认构造函数是否已被指定为私有,如果是,为什么?
我也检查了返回的 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?
事实并非如此。当您使用 no 构造函数定义 class 时,将为您生成一个默认的 no-args 构造函数。如果您提供构造函数,则不再生成此默认构造函数。换句话说,class 可能没有默认构造函数。
考虑到这一点,MimeKit.Header
class 提供了 6 个构造函数,其中 none 不带参数。因此,JSON.NET不知道如何实例化这个class,这就是为什么会出现异常。
由于您无法控制 MimeKit.Header
class,让 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
class 反序列化为 JObject
。然后,我们从 JObject
中选择 HeaderId
和 Value
以创建一个 Header
实例。
这里要注意:我对这个库了解不多。这可能不是实例化 Header
的最佳方式,而且我可能会不小心丢弃一些信息。我只做了一些非常基本的测试。
一旦你解决了这个问题,你就会 运行 进入另一个与不接受 null
值的 属性 setter 相关的问题。
具体来说,ResentMessageId
和 MimeVersion
属性在 setter 中具有逻辑,如果您提供 null
,则会抛出 ArgumentException
。这是一个问题,因为当实例化 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。
这里还有一个注释:我注意到即使我忽略了 MimeVersion
和 ResentMessageId
如果 headers 包含一个 MimeVersion
and/or ResentMessageId
header。我猜这是在 MimeMessage
的某个地方烤出来的,但同样,我对这个库并不完全熟悉。
所以要使用上面的 classes(仅在反序列化时),您可以这样做:
string someJsonString = "{ ... }";
MimeMessage deserialized = JsonConvert.DeserializeObject<MimeMessage>(
someJsonString, new JsonSerializerSettings
{
ContractResolver = new MimeMessageContractResolver(),
Converters = new JsonConverter[]
{
new MimeHeaderConverter()
}
});
通过一些基本测试,这似乎工作正常。您可能会 运行 在实际使用中遇到更多问题,所以不能保证。
希望这至少能让你入门。
我在反序列化 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);
据我所知,默认构造函数总是被创建,这让我有点难以理解,默认构造函数是否已被指定为私有,如果是,为什么?
我也检查了返回的 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?
事实并非如此。当您使用 no 构造函数定义 class 时,将为您生成一个默认的 no-args 构造函数。如果您提供构造函数,则不再生成此默认构造函数。换句话说,class 可能没有默认构造函数。
考虑到这一点,MimeKit.Header
class 提供了 6 个构造函数,其中 none 不带参数。因此,JSON.NET不知道如何实例化这个class,这就是为什么会出现异常。
由于您无法控制 MimeKit.Header
class,让 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
class 反序列化为 JObject
。然后,我们从 JObject
中选择 HeaderId
和 Value
以创建一个 Header
实例。
这里要注意:我对这个库了解不多。这可能不是实例化 Header
的最佳方式,而且我可能会不小心丢弃一些信息。我只做了一些非常基本的测试。
一旦你解决了这个问题,你就会 运行 进入另一个与不接受 null
值的 属性 setter 相关的问题。
具体来说,ResentMessageId
和 MimeVersion
属性在 setter 中具有逻辑,如果您提供 null
,则会抛出 ArgumentException
。这是一个问题,因为当实例化 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。
这里还有一个注释:我注意到即使我忽略了 MimeVersion
和 ResentMessageId
如果 headers 包含一个 MimeVersion
and/or ResentMessageId
header。我猜这是在 MimeMessage
的某个地方烤出来的,但同样,我对这个库并不完全熟悉。
所以要使用上面的 classes(仅在反序列化时),您可以这样做:
string someJsonString = "{ ... }";
MimeMessage deserialized = JsonConvert.DeserializeObject<MimeMessage>(
someJsonString, new JsonSerializerSettings
{
ContractResolver = new MimeMessageContractResolver(),
Converters = new JsonConverter[]
{
new MimeHeaderConverter()
}
});
通过一些基本测试,这似乎工作正常。您可能会 运行 在实际使用中遇到更多问题,所以不能保证。
希望这至少能让你入门。