Возврат таблиц данных в WCF / .NET

У меня есть служба WCF, из которой я хочу вернуть DataTable. Я знаю, что это часто очень обсуждаемая тема, насколько хорошей практикой является возврат DataTables. Давайте отложим это на мгновение.

Когда я создаю DataTable с нуля, как показано ниже, никаких проблем не возникает. Таблица создается, заполняется и возвращается клиенту, и все в порядке:

[DataContract]
public DataTable GetTbl()
{
    DataTable tbl = new DataTable("testTbl");
    for(int i=0;i<100;i++)
    {
        tbl.Columns.Add(i);
        tbl.Rows.Add(new string[]{"testValue"});
    }
    return tbl;
}

Однако как только я выхожу и нажимаю на базу данных для создания таблицы, как показано ниже, я получаю исключение CommunicationException «Базовое соединение было закрыто: соединение было закрыто неожиданно».

[DataContract]
public DataTable GetTbl()
{
    DataTable tbl = new DataTable("testTbl");
    //Populate table with SQL query

    return tbl;
}

Таблица правильно заполняется на стороне сервера. Она значительно меньше, чем тестовая таблица, которую я просмотрел и вернул, а запрос небольшой и быстрый - здесь нет проблем с таймаутами или большой передачей данных. Используются те же самые функции и DataContracts / ServiceContracts / BehaviorContracts.

Почему способ заполнения таблицы может иметь какое-либо отношение к успешному возврату таблицы?

Ответов (8)

Решение

Для тех, у кого есть подобные проблемы, я решил свою проблему. Было несколько раз.

  • As Darren suggested and Paul backed up, the Max..Size properties in the configuration needed to be enlarged. The SvcTraceViewer utility helped in determining this, but it still does not always give the most helpful error messages.
  • It also appears that when the Service Reference is updated on the client side, the configuration will sometimes not update properly (e.g. Changing config values on the server will not always properly update on the client. I had to go in and change the Max..Size properties multiple times on both the client and server sides in the course of my debugging)
  • For a DataTable to be serializable, it needs to be given a name. The default constructor does not give the table a name, so:

    return new DataTable();
    

    will not be serializable, while:

    return new DataTable("someName");
    

    will name the table whatever is passed as the parameter.

    Обратите внимание, что таблице можно присвоить имя в любое время, присвоив строку TableNameсвойству DataTable.

    var table = new DataTable();
    table.TableName = "someName";
    

Надеюсь, это кому-то поможет.

Я добавил Datable в набор данных и вернул таблицу вот так ...

DataTable result = new DataTable("result");

//linq to populate the table

Dataset ds = new DataSet();
ds.Tables.Add(result);
return ds.Tables[0];

Надеюсь, это поможет :)

Есть 3 причины неудачного возврата типа, как datatable в службах WCF.

  • Вы должны указать имя таблицы данных, например:

    MyTable=new DataTable("tableName");
    
  • Когда вы добавляете ссылку на клиентскую сторону службы WCF, выберите многоразовую dll system.data

  • Укажите атрибут datatableпеременной-члена, например

    [DataMember]
    public DataTable MyTable{ get; set; }
    

Вам нужен атрибут OperationContract (в интерфейсе) / Operation Behavior (в методе):

[ServiceContract]
public interface ITableProvider
{
    [OperationContract]
    DataTable GetTbl();
}


[OperationBehavior]
public DataTable GetTbl(){
    DataTable tbl = new DataTable("testTbl");
    //Populate table with SQL query

    return tbl;
}

Кроме того, в ... Я думаю, что конфигурация службы ... вы хотите указать, что ошибки могут отправляться. Возможно, вы столкнулись с ошибкой, что-то вроде слишком большого размера сообщения и т.д.

По умолчанию wsHttpBinding имеет квоту размера приема примерно 65 КБ, поэтому, если XML-код таблицы сериализованных данных больше этого, это вызовет ошибку (и я на 95% уверен, что таблица данных имеет размер более 65 КБ с данными в ней. ).

Вы можете изменить настройки квот для чтения и тому подобное в web.config / app.config или вы можете установить его для экземпляра привязки в коде. Но да, вероятно, в этом и заключается ваша проблема, если вы не меняли ее по умолчанию.

Члены WSHttpBindingBase - посмотрите на свойство ReaderQuotas, а также на свойство MaxReceivedMessageSize.

Лучший способ диагностировать подобные ошибки WCF (которые на самом деле мало что вам говорят) - включить трассировку. В свой файл web.config добавьте следующее:

  <system.diagnostics>
    <sources>
      <source name="System.ServiceModel" 
              switchValue="Information" 
              propagateActivity="true">
        <listeners>
          <add name="ServiceModelTraceListener" 
               type="System.Diagnostics.XmlWriterTraceListener, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" 
               initializeData="wcf-traces.svclog"/>
        </listeners>
      </source>
    </sources>
  </system.diagnostics>

Затем вы можете открыть полученный файл в служебной программе SvcTraceViewer.exe, которая входит в .NET Framework SDK (или с Visual Studio). На моем компьютере его можно найти в% PROGRAMFILES% \ Microsoft SDKs \ Windows \ v6.0A \ Bin \ SvcTraceViewer.exe.

Просто найдите сообщение об ошибке (выделенное жирным красным шрифтом), в котором конкретно будет рассказано, в чем заключается ваша проблема.

Я думаю, что Даррен, скорее всего, прав - значения по умолчанию, предоставленные для WCF, смехотворно малы, и если вы столкнетесь с ними, вы получите ошибки, которые может быть трудно отследить. Кажется, они появляются, как только вы пытаетесь сделать что-либо, кроме простого тестового примера. Я потратил больше времени, чем хотел бы признать, проблемы отладки, которые оказались связаны с различными настройками конфигурации (размера) как на клиенте, так и на сервере. Думаю, я изменил почти все из них, например. MaxBufferPoolSize, MaxBufferSize, MaxConnections, MaxReceivedMessageSize и т. Д.

При этом упомянутая утилита SvcTraceViewer великолепна. Я встречал несколько случаев, когда это было не так полезно, как мне хотелось бы, но в целом это хороший инструмент для анализа коммуникационного потока и ошибок.

Вероятно, вы исчерпали свою квоту - таблица данных превышает разрешенный максимальный размер пакета для вашего соединения.

Вероятно, вам нужно установить для MaxReceivedMessageSize и MaxBufferSize более высокие значения в вашем соединении.

Кроме установки максимальных значений для всех атрибутов привязки.

Убедитесь, что каждая таблица, которую вы передаете / возвращаете из веб-службы, должна иметь имя таблицы, то есть table.tablename свойство не должно быть пустым.