Подтвердить что ты не робот

Возврат данных в 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.

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

4b9b3361

Ответ 1

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

  • Как предложил Даррен, и Пол поддержал, свойства Max..Size в конфигурации необходимо было увеличить. Утилита SvcTraceViewer помогла в определении этого, но она по-прежнему не всегда дает наиболее полезные сообщения об ошибках.
  • Также появляется сообщение о том, что когда ссылка на службу обновляется на стороне клиента, конфигурация иногда не обновляется должным образом (например, изменение значений конфигурации на сервере не всегда будет корректно обновляться на клиенте. Мне пришлось войти и изменить Max..Size несколько раз на стороне клиента и сервера в ходе моей отладки)
  • Для того, чтобы DataTable мог быть сериализуемым, ему должно быть присвоено имя. Конструктор по умолчанию не дает таблице имя, поэтому:

    return new DataTable();
    

    не будет сериализуемым, а:

    return new DataTable("someName");
    

    будет указывать таблицу, которая передается как параметр.

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

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

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

Ответ 2

Лучший способ диагностики этих ошибок 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, которая входит в SDK.NET Framework (или с Visual Studio). На моей машине его можно найти в папке% PROGRAMFILES%\Microsoft SDK\Windows\v6.0A\Bin\SvcTraceViewer.exe.

Просто найдите сообщение об ошибке (выделено жирным красным цветом), и это точно скажет вам, в чем проблема.

Ответ 3

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

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

Ответ 4

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

DataTable result = new DataTable("result");

//linq to populate the table

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

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

Ответ 5

Атрибут, который вы хотите, - OperationContract (по интерфейсу)/Operation Behavior (on method):

[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 KB, поэтому, если XML-таблица с сериализованными данными больше, чем это, она выдаст ошибку (и я на 95% уверен, что таблица данных больше 65 KB с данными в нем).

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

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

Ответ 6

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

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

Ответ 7

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

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

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

  • Укажите атрибут в переменной datatable member, как

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

Ответ 8

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

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