C# не может десериализовать DataTable

У меня есть проект клиент / сервер, и я пытаюсь отправить через сокет DataTable(извлеченный из TableAdapter) с сервера на клиент. Мое пространство имен сервера - srvCentral, а мой клиент - appClient. Когда я пытаюсь десериализовать DataTable в клиенте, он выдает мне исключение Serialize, в котором говорится: "Невозможно найти сборку" srvCentral, Version=1.0.0.0, Culture= нейтральный, PublicKeyToken=null'. 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;
    }
}
}

1 ответ

Что я делаю неправильно?

вздох; 1: используя DataTable и 2: использование BinaryFormatter

давайте сначала возьмем последнее; BinaryFormatter является типо-ориентированным сериализатором. На самом деле, вам, вероятно, сойдет с рук, если бы вы просто использовали DataTable а не печатный DataTable подкласс, но BinaryFormtter в конечном счете, хочет одинаковые типы на каждом конце. А у тебя этого нет. И даже если бы вы это сделали, каждый раз, когда вы устанавливаете версию одного конца канала, все может стать немного… изворотливым (если вы не вложите в это дополнительную осторожность).

В качестве временного исправления для этого шага просто используйте 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. Все это очень хорошо работает и над сокетами.

Другие вопросы по тегам