簡體   English   中英

反序列化mimekit.MimeMessage對象

[英]Deserialising mimekit.MimeMessage Object

我在反序列化mimeKit.mimeMessage時遇到一些問題,該序列已序列化為JSON字符串並存儲在redis鍵值緩存中。

我能夠使用json.NET或Jil成功地序列化並存儲mimeMessage,但是當我進行反序列化時,會引發以下錯誤。

由json.NET拋出

找不到用於MimeKit.Header類型的構造函數。 一個類應該具有一個默認構造函數,一個帶有參數的構造函數或一個標有JsonConstructor屬性的構造函數。 路徑“ Headers [0] .Offset”,第1行,位置22。

我正在使用StackExchange.Redis方法stringGet來獲取序列化的對象,然后將RedisValue傳遞到Json.Net。 下面的代碼段:

RedisValue result = db.StringGet(key);

MimeMessage message = new MimeMessage();

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

據我了解,總是會創建一個默認的構造函數,這使我有點難以理解,是否可以將默認的構造函數指定為私有,如果可以,為什么?

我還檢查了返回的JSON字符串的格式,它是正確的。

謝謝你的幫助。

首先,要清理一下:

據我了解,總是會創建一個默認的構造函數,這使我有點難以理解,是否可以將默認的構造函數指定為私有,如果可以,為什么?

這不是真的。 當您定義沒有構造函數的類時,將為您生成一個默認的無參數構造函數。 如果提供構造函數,則不再生成此默認構造函數。 換句話說,一個類可能沒有默認的構造函數。


考慮到這一點, MimeKit.Header類提供了6個構造函數,這些構造函數都不帶任何參數。 因此,JSON.NET不知道如何實例化此類,這就是發生異常的原因。

由於您對MimeKit.Header類沒有任何控制權, 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值的屬性設置器有關的問題。

具體來說,如果您提供null ,則ResentMessageIdMimeVersion屬性在設置器中具有引發ArgumentException的邏輯。 這是一個問題,因為在實例化MimeMessage時,這些值可以為null。

一種解決方法是創建一個不包含那些屬性的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傳遞給這些屬性之一的設置器。

這里也要注意 :我注意到,即使當我忽略MimeVersionResentMessageId ,如果標頭包含MimeVersion和/或ResentMessageId標頭,它們仍然會被設置。 我猜想它已經被MimeMessageMimeMessage某個地方,但是同樣,我對這個庫並不完全熟悉。

因此,要使用上述類(僅在反序列化時),您可以這樣做:

string someJsonString = "{ ... }";

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

通過一些基本測試,這似乎可以正常工作。 您最終可能會在實際使用中遇到更多問題,因此無法保證。

希望這至少可以幫助您入門。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM