ServiceStack JSONシリアライザー:デフォルトのシリアライザーをグローバルに変更するにはどうすればよいですか?

Aug 21 2020

ServiceStack JSONシリアライザーが逆シリアル化に失敗し、NewtonsoftのJSON.NETがなんとか逆シリアル化に失敗する場合があります。デフォルトのシリアライザーをJSON.NETに置き換える明確な方法が見つからなかったため、グローバルですべてのクラスに対応します。

JsConfig<T>.SerializeFn うまくいくと思いますが、クラスごとであり、グローバルにすべてのクラスに必要です。

それ、どうやったら出来るの?

バックグラウンド

ServiceStack.Messaging.RedisMQソリューションとしてとRedisを使用しています。メッセージの送信には、次のアプローチを使用します。

using (var mqClient = MqClientFactory.Instance.CreateMessageQueueClient())
{

    var uniqueCallbackQ = "mq:c1" + ":" + Guid.NewGuid().ToString("N");
    var clientMsg = new Message<TRequest>(request)
    {
        ReplyTo = uniqueCallbackQ
    };

    mqClient.Publish(clientMsg);
    //Blocks thread on client until reply message is received
    responseMessage = mqClient.Get<TResponse>(uniqueCallbackQ, timeout);
}

メッセージを受信するための標準的なもの:

redisMqServer.RegisterHandler<TheRequest>(base.ExecuteMessage);

単純化すると、を含むRequestクラスがありpublic object Result {get; set;}、このプロパティはServiceStackでDictionary<string, object>、正しいタイプではなく、として逆シリアル化されます。

私は強く型付けされたオブジェクトを使用することを推奨していることをよく知っていますが、私の問題は、実際には外部通信用のクリーンなDTOを扱っていないことですが、内部オブジェクトの内部通信は、ポリモーフィズムとそのレガシーコードに大きく依存しており、新しいものを作成していません今のもの。

そのため、場合によっては、「オブジェクト」プロパティがあり、ServiceStackで逆シリアル化しても機能しません。タイプ情報がそこにあるので、機能すると思いましたが、機能しませんでした(わかりやすくするために以下の名前空間を削除しました)。

string ssJson = ServiceStack.Text.JsonSerializer.SerializeToString(getTextMessageTemplateObject);

// above produces: 

{
    "_Type": "Deviation",
    "Result": [{
            "__type": "TextMessageTemplate, AlfaCommons",
            "_Message": "test",
            "_Type": "Deviation",
        }
    ],
    "Success": true,
}

// And then, deserialize the json above:

GetTextMessageTemplate ssGetTextMessageTemplate = ServiceStack.Text.JsonSerializer.DeserializeFromString< 
GetTextMessageTemplate>(ssJson);

これはssGetTextMessageTemplate(わかりやすくするためにいくつかのプロパティを削除したことに注意してください):

上記のように、結果プロップは正しく逆シリアル化されませんでした。

JSON.NETを使用する場合、シリアル化されたJSONは次のとおりです。

{
    "$type": "GetTextMessageTemplate, AlfaCommons", "_Type": 4, "Result": { "$type": "System.Collections.Generic.List`1[[TextMessageTemplate, AlfaCommons]], System.Private.CoreLib",
        "$values": [{ "$type": "TextMessageTemplate, AlfaCommons",
                "_Message": "test",
                "_Type": 4,
            }
        ]
    }
}

デシリアライズ後、期待どおりに機能します。

そのため、代わりに上記の場合のJSON.NETシリアライザーを試してみたいと思います。

回答

mythz Aug 21 2020 at 17:18

ServiceStack.Redisは、オブジェクトのシリアル化をServiceStack.Textに強く依存しており、代替のJSONSerailizerを使用するためのグローバル置換をサポートしていません。

メッセージで任意のペイロードを送信するための1つの回避策は、string Resultプロパティでシリアル化されたJSONを送信することです。これは、JSON.NETを使用して逆シリアル化できます。

別の潜在的な回避策は、FromObjectDictionary Reflection Utilsを使用して、オブジェクトディクショナリを型指定されたDTOに変換し直すことです。例:

var result = objDictionary.FromObjectDictionary(theResultType);