Вопрос

У меня есть служба 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.

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

Это было полезно?

Решение

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

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

    return new DataTable();
    

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

    return new DataTable("someName");
    

    назовет таблицу так, как будет передано в качестве параметра.

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

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

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

Другие советы

Лучший способ диагностировать такого рода ошибки 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 SDKs\Windows\v6.0A\Bin\SvcTraceViewer.exe.

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

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

DataTable result = new DataTable("result");

//linq to populate the table

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

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

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

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

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

[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.

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

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

Существует 3 причины неудачного типа возврата: datatable в службах WCF

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

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

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

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

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

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top