Pregunta

Tengo un servicio WCF del cual quiero devolver un DataTable.Sé que este es a menudo un tema muy debatido, en cuanto a si devolver DataTables es una buena práctica o no.Dejemos eso de lado por un momento.

Cuando creo un DataTable desde cero, como se muestra a continuación, no hay ningún problema.La tabla se crea, se completa y se devuelve al cliente, y todo está bien:

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

Sin embargo, tan pronto como salgo y accedo a la base de datos para crear la tabla, como se muestra a continuación, aparece una excepción de comunicación "La conexión subyacente se cerró:La conexión se cerró inesperadamente."

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

    return tbl;
}

La tabla se está completando correctamente en el lado del servidor.Es significativamente más pequeña que la tabla de prueba que recorrí y devolví, y la consulta es pequeña y rápida; aquí no hay problemas con tiempos de espera o transferencias de datos grandes.Se utilizan exactamente las mismas funciones y contratos de datos/contratos de servicio/contratos de comportamiento.

¿Por qué la forma en que se completa la tabla tendría alguna relación con el retorno exitoso de la tabla?

¿Fue útil?

Solución

Para cualquiera que tenga problemas similares, he solucionado mi problema.Fue varias veces.

  • Como sugirió Darren y Paul respaldó, era necesario ampliar las propiedades Max..Size en la configuración.La utilidad SvcTraceViewer ayudó a determinar esto, pero no siempre muestra los mensajes de error más útiles.
  • También parece que cuando la Referencia de servicio se actualiza en el lado del cliente, la configuración a veces no se actualiza correctamente (p. ej.Cambiar los valores de configuración en el servidor no siempre se actualizará correctamente en el cliente.Tuve que entrar y cambiar las propiedades Max..Size varias veces tanto en el lado del cliente como en el del servidor durante el curso de mi depuración)
  • Para que un DataTable sea serializable, es necesario darle un nombre.El constructor predeterminado no le da un nombre a la tabla, por lo que:

    return new DataTable();
    

    no será serializable, mientras que:

    return new DataTable("someName");
    

    nombrará la tabla con el nombre que se pase como parámetro.

    Tenga en cuenta que a una tabla se le puede dar un nombre en cualquier momento asignando una cadena al TableName propiedad de la tabla de datos.

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

Ojalá eso ayude a alguien.

Otros consejos

La mejor manera de diagnosticar este tipo de errores de WCF (los que realmente no dicen mucho) es habilitar el seguimiento.En su archivo web.config, agregue lo siguiente:

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

Luego puede abrir el archivo resultante en la utilidad SvcTraceViewer.exe que viene en el SDK de .NET Framework (o con Visual Studio).En mi máquina, se puede encontrar en %PROGRAMFILES%\Microsoft SDKs\Windows\v6.0A\Bin\SvcTraceViewer.exe.

Simplemente busque un mensaje de error (en negrita y rojo) que le indicará específicamente cuál es su problema.

Agregué Datable a un conjunto de datos y devolví la tabla así...

DataTable result = new DataTable("result");

//linq to populate the table

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

Espero eso ayude :)

Además de establecer valores máximos para todos los atributos vinculantes.

Asegúrese de que cada tabla que pasa o regresa del servicio web debe tener un nombre de tabla, es decir, el table.tablename La propiedad no debe estar en blanco.

El atributo que desea es OperationContract (en la interfaz) / Operation Behavior (en el 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;
}

Además, en el...Creo que la configuración del servicio...desea especificar que se pueden enviar errores.Es posible que se encuentre con un error como que el tamaño del mensaje es demasiado grande, etc.Puedes solucionarlo modificando las cuotas de lectores y demás.

De forma predeterminada, wsHttpBinding tiene una cuota de tamaño de recepción de aproximadamente 65 KB, por lo que si el XML de la tabla de datos serializados es mayor que eso, arrojaría un error (y estoy 95 % seguro de que la tabla de datos tiene más de 65 KB con datos en ella). ).

Puede cambiar la configuración de las cuotas de lectores y demás en el web.config / app.config o puede configurarlo en una instancia vinculante en el código.Pero sí, probablemente ese sea tu problema, si no lo has cambiado de forma predeterminada.

Miembros de WSHttpBindingBase - Mire la propiedad ReaderQuotas así como la propiedad MaxReceivedMessageSize.

Probablemente haya superado su cuota: la tabla de datos es mayor que el tamaño de paquete máximo permitido para su conexión.

Probablemente necesites configurar Tamaño máximo del mensaje recibido y Tamaño máximo del búfer a valores más altos en su conexión.

Hay 3 razones para el tipo de devolución fallida como datatable en servicios WCF

  • Debe especificar el nombre de la tabla de datos como:

    MyTable=new DataTable("tableName");
    
  • Cuando agregue una referencia en el lado del cliente del servicio WCF, seleccione dll reutilizable system.data

  • Especificar atributo en datatable variable miembro como

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

Creo que lo más probable es que Darren tenga razón: los valores predeterminados proporcionados para WCF son ridículamente pequeños y, si los encuentras, terminarás con errores que pueden ser difíciles de rastrear.Parecen aparecer tan pronto como intentas hacer algo más allá de un simple caso de prueba.Perdí más tiempo del que me gustaría admitir al depurar problemas que resultaron estar relacionados con las diversas configuraciones (tamaño) tanto en el cliente como en el servidor.Creo que terminé modificándolos casi todos, ej.MaxBufferPoolSize, MaxBufferSize, MaxConnections, MaxReceivedMessageSize, etc.

Dicho esto, la utilidad SvcTraceViewer también mencionada es excelente.Me encontré con algunos casos en los que no fue tan útil como me hubiera gustado, pero en general es una buena herramienta para analizar el flujo de comunicaciones y los errores.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top