C# 反序列化mimekit.MimeMessage对象

C# 反序列化mimekit.MimeMessage对象,c#,json,json.net,mimekit,C#,Json,Json.net,Mimekit,我对序列化为JSON字符串并存储在redis键值缓存中的mimeKit.mimeMessage进行反序列化时遇到一些问题 我能够使用json.NET或Jil成功地序列化和存储mimessage,但是当我转到反序列化时,会抛出以下错误 由json.NET抛出 找不到用于类型MimeKit.Header的构造函数。一个类应该有一个默认构造函数、一个带参数的构造函数或一个标记有JsonConstructor属性的构造函数。路径“头[0]。偏移量”,第1行,位置22 我使用StackExchange.R

我对序列化为JSON字符串并存储在redis键值缓存中的mimeKit.mimeMessage进行反序列化时遇到一些问题

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

由json.NET抛出

找不到用于类型MimeKit.Header的构造函数。一个类应该有一个默认构造函数、一个带参数的构造函数或一个标记有JsonConstructor属性的构造函数。路径“头[0]。偏移量”,第1行,位置22

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

RedisValue result = db.StringGet(key);

MimeMessage message = new MimeMessage();

message = JsonConvert.DeserializeObject<MimeMessage>(result);
RedisValue结果=db.StringGet(键);
MimeMessage message=新的MimeMessage();
message=JsonConvert.DeserializeObject(结果);
我的理解是,默认构造函数总是被创建的,这让我很难理解,默认构造函数是否可以被指定为私有的,如果是,为什么

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


谢谢您的帮助。

首先,要解决一些问题:

我的理解是,默认构造函数总是被创建的,这让我很难理解,默认构造函数是否可以被指定为私有的,如果是,为什么

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


考虑到这一点,
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; } }
}
这样,我们就不会意外地将这些属性之一的
null
传递给setter

这里还有一个注意事项:我注意到,即使我忽略了
MimeVersion
ResentMessageId
标题,如果标题包含
MimeVersion
和/或
ResentMessageId
标题,它们仍然被设置。我猜这是在
MimeMessage
的某个地方烤出来的,但是我对这个库不是很熟悉

因此,要使用上述类(仅在反序列化时),您需要执行以下操作:

string someJsonString = "{ ... }";

MimeMessage deserialized = JsonConvert.DeserializeObject<MimeMessage>(
    someJsonString, new JsonSerializerSettings
    { 
        ContractResolver = new MimeMessageContractResolver(),
        Converters = new JsonConverter[] 
        { 
            new MimeHeaderConverter()
        }
    });
string someJsonString=“{…}”;
MimeMessage deserialized=JsonConvert.DeserializeObject(
一些JSONString,新的JsonSerializerSettings
{ 
ContractResolver=新的MIMessageContractResolver(),
转换器=新的JsonConverter[]
{ 
新的MimeHeaderConverter()
}
});
通过一些基本测试,这似乎效果良好。在实际使用中,您可能会遇到更多问题,因此无法保证


希望这至少能让你开始。

我想你可能需要
public override bool CanWrite{get{return false;}}
Wow,感谢你为这个答案付出了这么多的努力,尤其是解释。获取问题的解释而不仅仅是代码片段总是有益的。您将MimeMessage序列化到JSON或从JSON反序列化有什么原因吗?MIME本质上是复合文档的序列化格式,所以这对我来说没有多大意义。您可以使用message.WriteTo()和MimeMessage.Load()进行序列化和反序列化。嘿@jstedfast谢谢您的回复。我不知道mime是连载格式。建议使用writeTo方法写入字符串吗?正如我在问题中所说,我想将消息存储在redis键值缓存中,从我所读到的内容来看,json字符串似乎是实现这一点的首选方法。消息通常有多个字符集,尤其是来自西欧/美国以外的字符集,因此不能用单个字符集表示(因此不可能将它们表示为字符串)。我意识到这是一个相当老的问题,但我需要将它们保存到Mongo,为此我需要转换为字符串。
string someJsonString = "{ ... }";

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