Pergunta

Eu tenho um serviço WCF do qual desejo retornar um DataTable.Eu sei que este é frequentemente um tópico altamente debatido, na medida em que retornar ou não DataTables é uma boa prática.Vamos deixar isso de lado por um momento.

Quando crio um DataTable do zero, conforme abaixo, não há problema algum.A tabela é criada, preenchida e devolvida ao cliente, e está tudo bem:

[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;
}

Porém, assim que saio e vou ao banco de dados para criar a tabela, conforme abaixo, recebo uma CommunicationException "A conexão subjacente foi fechada:A conexão foi encerrada inesperadamente."

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

    return tbl;
}

A tabela está sendo preenchida corretamente no lado do servidor.Ela é significativamente menor do que a tabela de teste que percorri e retornei, e a consulta é pequena e rápida - não há problema aqui com tempos limite ou grandes transferências de dados.As mesmas funções exatas e DataContracts/ServiceContracts/BehaviorContracts estão sendo usadas.

Por que a maneira como a tabela está sendo preenchida teria alguma influência no retorno da tabela com êxito?

Foi útil?

Solução

Para qualquer pessoa com problemas semelhantes, resolvi meu problema.Foi várias vezes.

  • Como Darren sugeriu e Paul apoiou, as propriedades Max..Size na configuração precisavam ser ampliadas.O utilitário SvcTraceViewer ajudou a determinar isso, mas ainda nem sempre fornece as mensagens de erro mais úteis.
  • Parece também que quando a Referência de Serviço é atualizada no lado do cliente, a configuração às vezes não será atualizada corretamente (por exemplo,A alteração dos valores de configuração no servidor nem sempre será atualizada corretamente no cliente.Tive que entrar e alterar as propriedades Max..Size várias vezes no lado do cliente e do servidor durante minha depuração)
  • Para que um DataTable seja serializável, ele precisa receber um nome.O construtor padrão não dá um nome à tabela, então:

    return new DataTable();
    

    não será serializável, enquanto:

    return new DataTable("someName");
    

    nomeará a tabela conforme for passado como parâmetro.

    Observe que uma tabela pode receber um nome a qualquer momento, atribuindo uma string ao TableName propriedade do DataTable.

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

Espero que isso ajude alguém.

Outras dicas

A melhor maneira de diagnosticar esses tipos de erros do WCF (aqueles que realmente não dizem muito) é ativar o rastreamento.No seu arquivo web.config, adicione o seguinte:

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

Você pode então abrir o arquivo resultante no utilitário SvcTraceViewer.exe que vem no SDK do .NET Framework (ou com o Visual Studio).Na minha máquina, ele pode ser encontrado em %PROGRAMFILES%\Microsoft SDKs\Windows\v6.0A\Bin\SvcTraceViewer.exe.

Basta procurar uma mensagem de erro (em negrito vermelho) e ela informará especificamente qual é o seu problema.

Adicionei o Datable a um conjunto de dados e retornei a tabela assim ...

DataTable result = new DataTable("result");

//linq to populate the table

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

Espero que ajude :)

Além de definir valores máximos para todos os atributos de ligação.

Certifique-se de que cada tabela que você está passando/retornando do webservice deve ter um nome de tabela, ou seja, o table.tablename propriedade não deve ficar em branco.

O atributo que você deseja é OperationContract (na interface)/Operation Behavior (no método):

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


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

    return tbl;
}

Além disso, no...Acho que configuração do serviço...você deseja especificar que erros podem ser enviados.Você pode estar encontrando um erro semelhante ao tamanho da mensagem ser muito grande, etc.Você pode consertar isso alterando as cotas de leitores e coisas assim.

Por padrão, wsHttpBinding tem uma cota de tamanho de recebimento de 65 KB. Portanto, se o XML da tabela de dados serializada for maior que isso, ocorrerá um erro (e tenho 95% de certeza de que a tabela de dados tem mais de 65 KB com dados nela ).

Você pode alterar as configurações das cotas de leitores e outros itens no web.config / app.config ou você pode configurá-lo em uma instância de ligação no código.Mas sim, provavelmente é esse o seu problema, se você não o alterou por padrão.

Membros WSHttpBindingBase - Veja a propriedade ReaderQuotas e também a propriedade MaxReceivedMessageSize.

Você provavelmente estourou sua cota - a tabela de dados é maior que o tamanho máximo de pacote permitido para sua conexão.

Você provavelmente precisará definir MaxReceivedMessageSize e MaxBufferSize para valores mais altos em sua conexão.

Existem 3 motivos para falha no tipo de retorno, como datatable em serviços WCF

  • Você deve especificar o nome da tabela de dados como:

    MyTable=new DataTable("tableName");
    
  • Ao adicionar referência no lado do cliente do serviço WCF, selecione dll reutilizável system.data

  • Especifique o atributo em datatable variável de membro como

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

Acho que Darren provavelmente está correto - os valores padrão fornecidos para o WCF são ridiculamente pequenos e se você topar com eles, acabará com erros que podem ser difíceis de rastrear.Eles parecem aparecer assim que você tenta fazer algo além de um simples caso de teste.Perdi mais tempo do que gostaria de admitir problemas de depuração que estavam relacionados às várias configurações (tamanho) no cliente e no servidor.Acho que acabei modificando quase todos eles, ex.MaxBufferPoolSize, MaxBufferSize, MaxConnections, MaxReceivedMessageSize, etc.

Dito isto, o utilitário SvcTraceViewer também mencionado é ótimo.Encontrei alguns casos em que não foi tão útil quanto eu gostaria, mas no geral é uma ótima ferramenta para analisar o fluxo e os erros de comunicação.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top