Devolución de tablas de datos en WCF / .NET

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

Cuando creo una DataTable desde cero, como se muestra a continuación, no hay problemas de ningún tipo. La tabla se crea, se rellena 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 presiono la base de datos para crear la tabla, como se muestra a continuación, obtengo una CommunicationException “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ño que la tabla de prueba en la que hice un bucle y regresé, y la consulta es pequeña y rápida: aquí no hay problemas con los tiempos de espera o la transferencia de datos. Se están utilizando las mismas funciones exactas y DataContracts / ServiceContracts / BehaviorContracts.

¿Por qué la forma en que se está poblando la tabla tiene algún efecto sobre la tabla que regresa con éxito?

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

  • Como Darren sugirió y Paul hizo una copia de seguridad, las propiedades Max. Size de la configuración deben ampliarse. La utilidad SvcTraceViewer ayudó a determinar esto, pero todavía no proporciona 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 (por ejemplo, cambiar los valores de configuración en el servidor no siempre se actualizará correctamente en el cliente. Tuve que entrar y cambiar el máximo). Tamaño de las propiedades varias veces tanto en el lado del cliente como en el del servidor en el curso de mi depuración)
  • Para que una DataTable sea serializable, necesita un nombre. El constructor predeterminado no le da un nombre a la tabla, entonces:

     return new DataTable(); 

    no será serializable, mientras:

     return new DataTable("someName"); 

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

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

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

Espero que eso ayude a alguien.

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

           

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

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

Agregué el Datable a un conjunto de datos y devolví la tabla como tal …

 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 🙂

Aparte de establecer valores máximos para todos los atributos de enlace.

Asegúrese de que cada tabla que está pasando / devolviendo desde el servicio web debe tener un nombre de tabla, lo que significa que la propiedad table.tablename 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 … Creo que la configuración del servicio … quiere especificar que se pueden enviar errores. Es posible que esté alcanzando un error que es algo así como que el tamaño del mensaje es demasiado grande, etc. Puede solucionarlo modificando las cuotas del lector y demás.

Por defecto, wsHttpBinding tiene una cuota de tamaño de recepción de 65 KB, por lo que si el XML de la tabla de datos serializados es más que eso, arrojaría un error (y estoy seguro del 95% de que la tabla de datos contiene más de 65 KB) )

Puede cambiar la configuración de las cuotas del lector y app.config en el web.config / app.config o puede configurarlo en una instancia de enlace en el código. Pero sí, ese es probablemente tu problema, si no lo has cambiado por defecto.

Miembros de WSHttpBindingBase : observe la propiedad ReaderQuotas y la propiedad MaxReceivedMessageSize.

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

Probablemente necesite establecer MaxReceivedMessageSize y MaxBufferSize a valores más altos en su conexión.

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

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

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

  • Especifique el atributo en la variable de miembro datatable como

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

Creo que Darren probablemente esté en lo cierto: los valores predeterminados proporcionados para WCF son ridículamente pequeños y si te topas con ellos terminas 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 de lo que me gustaría admitir los problemas de depuración que resultaron estar relacionados con las diversas configuraciones (tamaño) en el cliente y el servidor. Creo que terminé modificando casi todos, ej. MaxBufferPoolSize, MaxBufferSize, MaxConnections, MaxReceivedMessageSize, etc.

Habiendo dicho eso, 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.