4

現在のServiceStackをprotobufシリアル化で使用しています。

応答をキャッシュするためにICacheClientを追加すると、キャッシュクライアントから送信されたバイナリ応答は、キャッシュクライアントがない元の応答とは異なるエンコーディング/バイナリシリアル化になります。

これにより、プリコンパイルされたデシリアライザーを使用しているクライアント側でデシリアライズの問題が発生します。

たとえば、このprotobuf例外は、ServiceStackサーバー側でICacheClientを使用するときにクライアント側で発生します。

OverflowException: Number overflow.
ProtoBuf.ProtoReader.TryReadUInt32VariantWithoutMoving (Boolean trimNegative, System.UInt32& value)
ProtoBuf.ProtoReader.ReadUInt32Variant (Boolean trimNegative)
ProtoBuf.ProtoReader.ReadUInt32 () MyModelSerializer.Read (My.Models.MyDataModel , ProtoBuf.ProtoReader )

(これはランダムな例外だと思います。他の例外も発生する可能性があります。これを例として取り上げてください。)

この動作は、MemoryCacheClientとRedisキャッシュクライアントの両方で同じです。

これが私がprotobufを初期化する方法です:

ContentTypeFilters.Register(ContentType.ProtoBuf,
                        (reqCtx, res, stream) => ProtoBuf.Serializer.NonGeneric.Serialize(stream, res),
                         ProtoBuf.Serializer.NonGeneric.Deserialize);

キャッシュクライアントは次のように初期化されます。

container.Register<ICacheClient>(new MemoryCacheClient());

(または、このガイドに従ってRedisを実行します)。

これは、ネットワークを介してキャッシュされたprotobufシリアル化されたデータがどのように見えるかであり、キャッシュされていないデータとは異なります: バイナリ差分 Big Image

キャッシュされていない応答は、エンコード/シリアル化が異なるようです。

このエンコーディングの問題について、RedisまたはMemory-ICacheClientをprotobufと互換性を持たせるためにできることはありますか?


更新:私は少し調査しました、これらは私の発見です:

  • キャッシュプロバイダー内に保存するために(Redis os Memoryであるかどうかに関係なく)、protobufバイナリストリームは、HttpResponseFilter->SerializeToStringのStreamReaderを介して「BOMなしのUTF8」を使用して文字列に「変換」されます。 -> Cache()。

  • 最初の問題:CacheClientExtensions-> Cache()は、文字列にシリアル化されたDTOを返しますが、protobufが逆シリアル化することはまだ不可能です。最初の解決策:CacheClientExtensions-> Cache()で元のDTOを返します。ただし、キャッシュされた応答はまだ適切に逆シリアル化されていないため、これはキャッシュされていない最初の応答に対してのみ機能します。これは私たちを

  • 2番目の問題:データをキャッシュから再度取得するには、最初にデータをキャッシュに入れるために、protobufのバイナリデータの正しい文字列シリアル化が必要です。base64経由で動作することはわかっています。

  • 3番目の問題:現在、実行時にHttpResponseFilter-> SerializeToStringでStreamReaderを介して現在のストリームから文字列への変換を置き換える方法はないようですが、私は正しいですか?

  • 4番目の問題:データをキャッシュから取得するときは、再度base64でデコードする必要があります。

4

1 に答える 1

1

ServiceStackコードを調べていましたが、要件を実現するための既存の可能性は見つかりませんでした(何かを見落とさなかったことを本当に望んでいます)。

そこで、ServiceStackにいくつかの変更を加えました。これにより、カスタムTextSerializerを使用できるようになります。この変更は、DTOをキャッシュクライアントにプッシュするためにシリアル化して文字列に変換するために使用されます。

ここで私の差分を参照してください: https ://github.com/derFunk/ServiceStack/commit/93f62c7d7e44a303c88a81c3096b9757daba4c7c

それは完全にテストされていない可能性があり、まだ非常にprotobufに焦点を当てていますが、私の目的のために機能しています。

一部のServiceStack忍者が私が行っていることを確認できれば幸いです。おそらく、プルリクエストになってしまうでしょう。

于 2012-08-28T15:42:54.117 に答える