文脈は以下の通り
- コードを別のプロジェクトに移動してリファクタリングしたい
- このコードの一部は、複数のエンドポイント間でデータを送受信するために使用されるシリアライズ可能な DTO で構成されています
- コードを移動すると、シリアライゼーションが壊れます (したがって、アプリケーションの古いバージョンとの下位互換性はありません)
この問題の解決策は、あるタイプから別のタイプにある意味で「リダイレクト」できるようにする SerializationBinder です。
したがって、このニーズを満たすために SerializationBinder を作成したいと思います。ただし、次の要件を満たす必要があります。
- SerializationBinder への入力は、古い型から新しい型へのマッピングのリストである必要があります。マッピングには、古いアセンブリ名 (バージョンなし、公開キー トークンなし) と型の古い完全な名前 (名前空間と名前)、および新しいアセンブリ名と型の新しい完全な名前を含める必要があります。
- 入力にある型の場合、アセンブリのバージョン番号は無視する必要があります
- 入力にジェネリックを含める必要なく、型がジェネリック (リスト、ディクショナリなど) にある場合は、ジェネリックを処理する必要があります。
- 入力に含まれていないもの (つまり、移動していない型や、たとえばデータセットのような .NET 型) については、既定でバイナリ シリアライザーのすぐに使えるアルゴリズムを使用する必要があります。
これは可能ですか、それとも私は夢を見ていますか? すでにこれを行っているものはありますか?これはよくある問題だと思います。
これまでのところ、3 を実行する簡単な方法はなく、4 を実行する方法もまったくありません。
ここに試みがあります
public class SmartDeserializationBinder : SerializationBinder
{
/// <summary>
/// Private class to handle storing type mappings
/// </summary>
private class TypeMapping
{
public string OldAssemblyName { get; set; }
public string OldTypeName { get; set; }
public string NewAssemblyName { get; set; }
public string NewTypeName { get; set; }
}
List<TypeMapping> typeMappings;
public SmartDeserializationBinder()
{
typeMappings = new List<TypeMapping>();
}
public void AddTypeMapping(string oldAssemblyName, string oldTypeName, string newAssemblyName, string newTypeName)
{
typeMappings.Add(new TypeMapping()
{
OldAssemblyName = oldAssemblyName,
OldTypeName = oldTypeName,
NewAssemblyName = newAssemblyName,
NewTypeName = newTypeName
});
}
public override Type BindToType(string assemblyName, string typeName)
{
//Need to handle the fact that assemblyName will come in with version while input type mapping may not
//Need to handle the fact that generics come in as mscorlib assembly as opposed to the assembly where the type is defined.
//Need to handle the fact that some types won't even be defined by mapping. In this case we should revert to normal Binding... how do you do that?
string alternateAssembly = null;
string alternateTypeName = null;
bool needToMap = false;
foreach (TypeMapping mapping in typeMappings)
{
if (typeName.Contains(mapping.OldTypeName))
{
alternateAssembly = mapping.NewAssemblyName;
alternateTypeName = mapping.NewTypeName;
needToMap = true;
break;
}
}
if (needToMap)
{
bool isList = false;
if (typeName.Contains("List`1"))
isList = true;
// other generics need to go here
if (isList)
return Type.GetType(String.Format("System.Collections.Generic.List`1[[{0}, {1}]]", alternateTypeName, alternateAssembly));
else
return Type.GetType(String.Format("{0}, {1}", alternateTypeName, alternateAssembly));
}
else
return null; // this seems to do the trick for binary serialization, but i'm not sure if it is supposed to work
}
}