Сведения о вопросе

Killer

13:59, 13th August, 2020

Теги

c#   .net   wcf   web-services   datatable    

Возвращение DataTables в WCF/.NET

Просмотров: 543   Ответов: 8

У меня есть сервис 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 "The underlying connection was closed: The connection was closed unexpectedly."

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

    return tbl;
}

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

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



  Сведения об ответе

baggs

02:33, 16th August, 2020

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

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

    return new DataTable();
    

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

    return new DataTable("someName");
    

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

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

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

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


  Сведения об ответе

DO__IT

07:08, 5th August, 2020

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

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


  Сведения об ответе

PROGA

08:43, 29th August, 2020

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

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


  Сведения об ответе

darknet

13:25, 20th August, 2020

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

DataTable result = new DataTable("result");

//linq to populate the table

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

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


  Сведения об ответе

qwerty101

15:31, 10th August, 2020

Нужный атрибут-OperationContract (on interface) / поведение операции (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.


  Сведения об ответе

baggs

12:06, 3rd August, 2020

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

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


  Сведения об ответе

PAGE

07:55, 29th August, 2020

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

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

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

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

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


  Сведения об ответе

pumpa

16:45, 16th August, 2020

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

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


Ответить на вопрос

Чтобы ответить на вопрос вам нужно войти в систему или зарегистрироваться