Возвращение DataTables в 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 используются.

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

15.08.2008 20:26:01
8 ОТВЕТОВ

Нужный атрибут: 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.

3
25.07.2015 21:51:23

Лучший способ диагностировать такие ошибки 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.

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

15
23.08.2008 18:56:50
Вы можете найти файл журнала wcf-traces.svclogв Debugпапке вашего проекта.
Daniel Bonetti 20.12.2017 19:04:22

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

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

0
2.09.2008 14:18:57
РЕШЕНИЕ

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

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

    return new DataTable();

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

    return new DataTable("someName");

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

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

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

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

82
23.06.2015 15:28:36
Очень странно с названием чтоли. У меня была такая же проблема. Установка имени в DataTable решила это ... Странно.
MartinHN 1.08.2009 17:52:30
+1 за имя таблицы. Я посмотрел на возврат HTTP в Fiddler, и VS использует это имя таблицы для генерации пользовательского типа данных. Если имя пустое, я думаю, оно пытается использовать пустое имя для этого пользовательского типа данных и просто выдает ошибки.
akatakritos 21.12.2011 18:37:20
Отличный вопрос и отличный ответ. Я помню эту проблему с чем-то другим раньше, я не могу вспомнить, я думаю, что это были просто классические веб-сервисы. Я не хочу открывать банку с червями, но я не чувствую себя виноватым, используя DataTables через канал, потому что, если я использую его только для отображения информации, я не думаю, что это вообще имеет значение. Когда вы начинаете передавать DataTables и DataRows в качестве параметров, то есть когда они становятся основными @ # $ # (* @% _ up. Объекты всегда безопаснее, но если ваши данные часто изменяются из-за того, что человек принимает решения скитзо - тогда я не не вижу вреда только для демонстрации.
dyslexicanaboko 1.09.2012 00:05:55
Святое дерьмо на люльке ... TableName ... Я обсуждаю проблемы WCF в течение нескольких часов (дней?), И я думаю, что это является основной причиной. Он голос за почти 10-летний ответ.
WernerCD 30.05.2017 01:10:07

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

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

2
24.10.2008 13:33:35

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

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

5
25.07.2015 21:52:42

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

DataTable result = new DataTable("result");

//linq to populate the table

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

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

5
24.10.2011 08:29:51
В моем случае DataTable, созданный в результате запроса к базе данных, работал нормально, но у него всегда были проблемы с DataTable, созданным в моем коде. Это было решено, когда я добавил эту таблицу во вновь созданный набор данных. Это довольно странно. Я считаю, что это какая-то ошибка в сериализации Microsoft.
Softec 14.03.2017 15:12:37

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

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

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

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

    [DataMember]
    public DataTable MyTable{ get; set; }
1
19.12.2016 04:49:58