Сериализация "System.Collections.Generic.List`1" BindToType
У меня есть веб-сервис, который выполняет поиск и возвращает клиенту следующее в виде массива байтов:
[Serializable]
public class MyFile
{
public byte[] Data;
public string FileName;
}
То есть я возвращаю список (Of MyFile) клиенту.
Это потребляется клиентом со следующим TYPENAME
System.Collections.Generic.List`1[[NorwayTaxService.Streaming+MyFile, NorwayTaxService, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]]
с именем сборки:
mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
Я использую следующие два класса для привязки для десериализации:
[Serializable]
public class MyFileLocal : ISerializable
{
public byte[] Data;
public string FileName;
// The security attribute demands that code that calls
// this method have permission to perform serialization.
[SecurityPermissionAttribute(SecurityAction.Demand, SerializationFormatter = true)]
void ISerializable.GetObjectData(SerializationInfo info, StreamingContext context)
{
info.AddValue("Data", Data);
info.AddValue("FileName", FileName);
}
// The security attribute demands that code that calls
// this method have permission to perform serialization.
[SecurityPermissionAttribute(SecurityAction.Demand, SerializationFormatter = true)]
private MyFileLocal(SerializationInfo info, StreamingContext context)
{
Data = (byte[])info.GetValue("Data", Data.GetType());
FileName = info.GetString("FileName");
}
}
sealed class MyFileWebToLocalVersionBinder : SerializationBinder
{
public override Type BindToType(string assemblyName, string typeName)
{
Type typeToDeserialize = null;
// For each assemblyName/typeName that you want to deserialize to
// a different type, set typeToDeserialize to the desired type.
String assemVer1 = Assembly.GetExecutingAssembly().FullName;
String typeVer1 = "NorwayTax.Streaming+MyFile";
if (assemblyName == assemVer1 && typeName == typeVer1)
{
// To use a type from a different assembly version,
// change the version number.
// To do this, uncomment the following line of code.
// assemblyName = assemblyName.Replace("1.0.0.0", "2.0.0.0");
// To use a different type from the same assembly,
// change the type name.
typeName = "MyFileLocal";
}
typeToDeserialize = Type.GetType(String.Format("{0}, {1}", typeName, assemblyName));
return typeToDeserialize;
}
}
Но из-за моей жизни, и, судя по многим, многим вариациям в выражении GETTYPE, мой TYPE всегда равен NULL.
Например, в посте на STACKOVERFLOW я пытался:
typeToDeserialize = Type.GetType(String.Format("{0}, {1}", "System.Collections.Generic.List`1[[NorwayTax.Streaming+MyFile, NorwayTax]]", assemblyName));
Но это не сработало:(
1 ответ
Тип объекта, который я пытался десериализовать, не существовал в клиентском приложении / сборке. Я думал, что с помощью SerializationBinder
Я был бы в состоянии бросить это в подобный объект.
Вот объект, который является сериализованным списком / коллекцией:
using System;
namespace NorwayTax
{
public class NorwayTaxFiles
{
[Serializable]
public class NorwayFile
{
public string FileName { set; get; }
public byte[] Data { set; get; }
}
}
}
и, возможно, его можно собрать в похожую коллекцию, но я не смог этого добиться.
В конце концов я выделил вышеприведенное в свою собственную DLL, на которую ссылались и моя веб-служба, и клиент, и она работала без нареканий и без необходимости SerializationBinder
,
Наконец, весь смысл этого упражнения заключался в передаче из веб-сервиса нескольких файлов за один проход с использованием инструментов Framework. Интересно, что файлы, которые я передал, уже сжаты с помощью 7z, но разбиты на части, согласно бизнес-требованиям, в набор архивов (.001, .002 и т. Д.).
Источником вдохновения для моего решения послужил следующий ответ: вы должны действительно определить библиотеку классов, содержащую в ней ссылку на ту же сборку.