クライアント/サーバープロジェクトがあり、サーバーからクライアントにDataTable(TableAdapterから抽出)をソケット経由で送信しようとしています。サーバーの名前空間はsrvCentralで、クライアントはappClientです。クライアントでDataTableを逆シリアル化しようとすると、シリアル化例外がスローされ、アセンブリが見つかりません'srvCentral、Version = 1.0.0.0、Culture = neutral、PublicKeyToken = null'とグーグルで検索し、AssemblyResolveの制御などを試しました。 svchostがハングして強制的に閉じ、次のようなバインダーを使用します。
sealed class AllowAllAssemblyVersionsDeserializationBinder : SerializationBinder
{
public override Type BindToType(string assemblyName, string typeName)
{
Type typeToDeserialize = null;
String currentAssembly = Assembly.GetExecutingAssembly().FullName;
// In this case we are always using the current assembly
assemblyName = currentAssembly;
// Get the type using the typeName and assemblyName
typeToDeserialize = Type.GetType(String.Format("{0}, {1}",
typeName, assemblyName));
return typeToDeserialize;
}
}
そして、例外はまだそこにあります... DataTableがどこでも逆シリアル化可能であると想定されていませんでしたか?私は何が間違っているのですか?
私のシリアル化コードは次のとおりです。
public byte[] Serializar(Object item)
{
BinaryFormatter formatter = new BinaryFormatter();
MemoryStream ms = new MemoryStream();
formatter.Serialize(ms, item);
return ms.ToArray();
}
public Object Deserializar(byte[] buffer)
{
BinaryFormatter formatter = new BinaryFormatter();
MemoryStream ms = new MemoryStream(buffer);
formatter.AssemblyFormat = System.Runtime.Serialization.Formatters.FormatterAssemblyStyle.Simple;
formatter.Binder = new AllowAllAssemblyVersionsDeserializationBinder();
Object a = formatter.Deserialize(ms);
return a;
}
sealed class AllowAllAssemblyVersionsDeserializationBinder : SerializationBinder
{
public override Type BindToType(string assemblyName, string typeName)
{
Type typeToDeserialize = null;
String currentAssembly = Assembly.GetExecutingAssembly().FullName;
// In this case we are always using the current assembly
assemblyName = currentAssembly;
// Get the type using the typeName and assemblyName
typeToDeserialize = Type.GetType(String.Format("{0}, {1}",
typeName, assemblyName));
return typeToDeserialize;
}
}
少し掘り下げた後、私はこれで問題を解決しました。
それはそれを解決するためのより良い方法ではありませんが、問題を回避するための簡単な方法です。小さなことならそれで十分です。表示コンテンツのみのテーブルからデータを取得する場合は、これを使用します。
namespace YourLibrary
{
[Serializable]
public class Tabela: ISerializable
{
protected ArrayList colNames;
protected ArrayList colTypes;
protected ArrayList dataRows;
public Tabela()
{
}
public Tabela (DataTable dt)
{
colNames = new ArrayList();
colTypes = new ArrayList();
dataRows = new ArrayList();
// Insert column information (names and types)
foreach(DataColumn col in dt.Columns)
{
colNames.Add(col.ColumnName);
colTypes.Add(col.DataType.FullName);
}
// Insert rows information
foreach(DataRow row in dt.Rows)
dataRows.Add(row.ItemArray);
}
public Tabela(SerializationInfo info, StreamingContext context)
{
colNames = (ArrayList)info.GetValue("colNames",typeof(ArrayList));
colTypes = (ArrayList)info.GetValue("colTypes",typeof(ArrayList));
dataRows = (ArrayList)info.GetValue("dataRows",typeof(ArrayList));
}
void ISerializable.GetObjectData(SerializationInfo info, StreamingContext context)
{
info.AddValue("colNames", colNames);
info.AddValue("colTypes", colTypes);
info.AddValue("dataRows", dataRows);
}
public DataTable GenerateDataTable()
{
DataTable dt = new DataTable();
// Add columns
for(int i=0; i<colNames.Count; i++)
{
DataColumn col = new DataColumn(colNames[i].ToString(),
Type.GetType(colTypes[i].ToString() ));
dt.Columns.Add(col);
}
// Add rows
for(int i=0; i<dataRows.Count; i++)
{
DataRow row = dt.NewRow();
row.ItemArray = (object[]) dataRows[i];
dt.Rows.Add(row);
}
dt.AcceptChanges();
return dt;
}
}
}