2

クライアント/サーバープロジェクトがあり、サーバーからクライアントに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;
    }
}
}
4

1 に答える 1

13

私は何が間違っているのですか?

はぁ; 1:を使用しDataTable、2:を使用するBinaryFormatter

最初に後者を取り上げましょう。BinaryFormatterタイプ中心のシリアライザーです。実際には、型付きサブクラスでDataTableはなく単に使用している場合はおそらくこれを回避できたでしょうが、最終的には両端でまったく同じ型が必要になります。そして、あなたはそれを持っていません。そして、たとえそうだとしても、パイプの一方の端をバージョン管理するたびに、物事は少し...危険になる可能性があります(これに特別な注意を払わない限り)。 DataTableBinaryFormtter

一時的な修正として、このステップでDataTableは、型指定されたサブクラスではなく使用するだけでDataTable、おそらく機能します。

しかし、それDataTableまた、投げるのがかなり厄介なことでもあります-かなり不器用で、目的がとても一般的です。それが提供するもの(特に動的列)が必要な場合は、おそらく一押しですが、ほとんどの場合、基本的なPOCO/DTOモデルを使用する方がはるかに望ましいでしょう。これは、ほとんどのIPCツールを含め、クライアント/サーバー境界で表現するのも簡単です。たとえば、次のPOCO / DTOクラス(またはそれらのリスト)は非常に使いやすいです。

public class Order {
    public int OrderID {get;set;}
    public string Reference {get;set;}
    ...
}

個人的には、特定のタイプに煩わされないシリアライザーを使用して、より単純なクラスベースのモデルに切り替えることを検討することを強くお勧めします。XmlSerializerまたはJavascriptSerializerうまく機能します。小さくて効率的なデータが必要な場合は、protobuf-netも一見の価値があります。これらはすべて、ソケットでも非常にうまく機能します。

于 2012-05-24T10:20:42.047 に答える