3

最新のprotobuf-netlibをprotobuf-netmemcacheプロバイダーで使用しています。カスタムタイプのMyClassのリストをシリアル化する必要があります

[ProtoContract]
public class MyClass{
  [ProtoMember(1)]
  public int a {get; set;}
  [ProtoMember(2)]
  public int b {get; set;}
}

だから私は保存/取得する必要があります:

List<MyClass> myList

値がprotobufを介して保存され、キャッシュから取得されると、すべてうまくいきます。ただし、値がmemcacheに(正しいprotobuf形式で)保存され、その後、別のスレッド/アプリから値が取得された場合、タイプフィールドのNullReferenceExceptionsが原因で、キャッシュの逆シリアル化が失敗します。

したがって、setが最初に実行されると、シリアル化された値のタイプがtypeCache変数に格納され、そのディクショナリから取得されます。ただし、値がmemcacheに存在するが、現在のスレッドに設定されていない場合typeCache varにはそのタイプが含まれず、逆シリアル化時にNullReferenceがスローされます。

これまたはいくつかの回避策を修正する方法はありますか?

より詳細な調査:で実装されたenyimのシリアル化/逆シリアル化プロセスProtoTranscoder.csNetTranscoderを持つクラスが含まれていDictionary<ArraySegment<byte>, Type> typeCacheます。したがって、setが最初になると、シリアル化されたタイプ(つまり)はvarにList<MyClass>格納され、すべてうまくいきます。typeCache値がmemcacheに存在するが、逆シリアル化時に現在のアプリ/スレッドに設定されていない場合、次のコードで取得されます。

type = Type.GetType(enc.GetString(buffer, keyOffset, len));
byte[] standaloneBuffer = new byte[len];
Buffer.BlockCopy(buffer, keyOffset, standaloneBuffer, 0, len);
key = new ArraySegment<byte>(standaloneBuffer, 0, len);
sync.EnterWriteLock();
try
   {
        // did somebody beat us to it?
        Type tmp;
        if (typeCache.TryGetValue(key, out tmp)) return tmp;
        typeCache.Add(key, type);
        return type;   <-- Here it returns null, if type not present in typeCache
   }
finally
   {
        sync.ExitWriteLock();
   }

そのエラーを再現するには:

  1. リストアイテム
  2. いくつかのリストを作成してmemcacheに保存します(構成されたprototranscoderを使用)
  3. 現在のアプリを再起動します(または別のスレッドを開始します)
  4. それらの「別のスレッド」からmemcacheからキーで値を取得してみてください

このエラーのスタックトレースは次のとおりです。[ArgumentNullException:値をnullにすることはできません。パラメータ名:タイプ]

   ProtoBuf.Meta.TypeModel.PrepareDeserialize(Object value, Type& type) in c:\Dev\protobuf-net\protobuf-net\Meta\TypeModel.cs:592
   ProtoBuf.Meta.TypeModel.Deserialize(Stream source, Object value, Type type, SerializationContext context) in c:\Dev\protobuf-net\protobuf-net\Meta\TypeModel.cs:577
   ProtoBuf.Caching.Enyim.NetTranscoder.Enyim.Caching.Memcached.ITranscoder.Deserialize(CacheItem item) in c:\Users\akureniov\work\protobuf-net-1\protobuf-net.Enyim\protobuf-net.Enyim\ProtoTranscoder.cs:109
   Enyim.Caching.MemcachedClient.PerformTryGet(String key, UInt64& cas, Object& value) +179
   Enyim.Caching.MemcachedClient.TryGet(String key, Object& value) +42
   Enyim.Caching.MemcachedClient.Get(String key) +15
4

2 に答える 2

3

Marc Gravellの助けを借りて、ProtoTranscoder.csのタイプトリミングに「バグ」が見つかりました。NetTranscoder:void WriteType(MemoryStream ms、Type type)。このコードブロックは、カットが多すぎるため、エラーが発生します。

int i = typeName.IndexOf(','); // first split
if (i >= 0) { i = typeName.IndexOf(',', i + 1); } // second split
if (i >= 0) { typeName = typeName.Substring(0, i); } // extract type/assembly only

単純なタイプではうまく機能しましたが、リスト、辞書などでは失敗します。

これを回避するには、正規表現を使用して、不要な情報(カルチャ、publickkeytokenなど)をカットすることをお勧めします。したがって、ここに置換(上の行をこれに置き換える必要があります)、静かな失礼ですが、ほとんどの場合は機能します:

typeName = Regex.Replace(typeName, @", Version=\d+.\d+.\d+.\d+", string.Empty);
typeName = Regex.Replace(typeName, @", Culture=\w+", string.Empty);
typeName = Regex.Replace(typeName, @", PublicKeyToken=\w+", string.Empty);

この正規表現は、カスタムタイプに必要なタイプのアセンブリをカットしません。ただし、標準タイプの場合mscorlibはそうです。ほとんどの場合、別の行を追加することで安全に削除できます。

typeName = Regex.Replace(typeName, @", mscorlib", string.Empty);
于 2013-02-19T13:48:37.583 に答える
0

memcacheが理解できないと思うのでProtoContract、マークを付けてみてくださいDataContract

于 2013-02-13T20:22:10.683 に答える