Контекст следующий
- Я хочу провести рефакторинг кода, перемещая его в разные проекты.
- Часть этого кода состоит из сериализуемых 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
}
}