Restituire DataTable in WCF / .NET

Ho un servizio WCF da cui voglio restituire un DataTable. So che questo è spesso un argomento molto dibattuto, per quanto riguarda il fatto che restituire DataTable sia una buona pratica. Mettiamola da parte per un momento.

Quando creo un DataTable da zero, come di seguito, non ci sono problemi di sorta. La tabella viene creata, popolata e restituita al client, e tutto va bene:

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

Tuttavia, non appena esco e colpisco il database per creare la tabella, come di seguito, ottengo una CommunicationException “La connessione sottostante è stata chiusa: la connessione è stata chiusa in modo imprevisto.”

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

La tabella viene popolata correttamente sul lato server. È significativamente più piccolo della tabella di test che ho passato e restituito, e la query è piccola e veloce – non ci sono problemi qui con timeout o grandi trasferimenti di dati. Vengono utilizzate le stesse esatte funzioni e DataContracts / ServiceContracts / BehaviorContracts.

Perché il modo in cui viene compilato il tavolo influisce positivamente sul rendimento della tabella?

Per chiunque abbia problemi simili, ho risolto il mio problema. Era multiplo.

  • Come suggerito da Darren e Paul, le proprietà Max..Size nella configurazione dovevano essere ingrandite. L’utilità SvcTraceViewer ha aiutato a determinare ciò, ma non sempre fornisce i messaggi di errore più utili.
  • Inoltre, quando la Service Reference viene aggiornata sul lato client, la configurazione a volte non si aggiorna correttamente (ad esempio, la modifica dei valori di configurazione sul server non si aggiornerà sempre correttamente sul client. Proprietà delle dimensioni più volte sia sul lato client che su server nel corso del mio debugging)
  • Perché un DataTable sia serializzabile, deve essere assegnato un nome. Il costruttore predefinito non fornisce un nome alla tabella, quindi:

     return new DataTable(); 

    non sarà serializzabile, mentre:

     return new DataTable("someName"); 

    chiamerà la tabella qualunque sia passato come parametro.

    Si noti che a una tabella può essere assegnato un nome in qualsiasi momento assegnando una stringa alla proprietà TableName del DataTable.

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

Spero che questo aiuti qualcuno.

Il modo migliore per diagnosticare questo tipo di errori WCF (quelli che non ti dicono molto) è abilitare la traccia. Nel tuo file web.config, aggiungi quanto segue:

           

È quindi ansible aprire il file risultante nell’utilità SvcTraceViewer.exe disponibile in .NET Framework SDK (o con Visual Studio). Sulla mia macchina, può essere trovato in% PROGRAMFILES% \ Microsoft SDK \ Windows \ v6.0A \ Bin \ SvcTraceViewer.exe.

Basta cercare un messaggio di errore (in grassetto rosso) e questo ti dirà in modo specifico quale sia il tuo problema.

Ho aggiunto il Datable a un set di dati e ho restituito la tabella in questo modo …

 DataTable result = new DataTable("result"); //linq to populate the table Dataset ds = new DataSet(); ds.Tables.Add(result); return ds.Tables[0]; 

Spero che sia d’aiuto 🙂

Altro che impostare i valori massimi per tutti gli attributi di rilegatura.

Assicurati che ogni tabella che stai passando / ritornando da webservice abbia un nome di tabella, il che significa che la proprietà table.tablename non dovrebbe essere vuota.

L’attributo desiderato è OperationContract (sull’interfaccia) / Operation Behaviour (sul metodo):

 [ServiceContract] public interface ITableProvider { [OperationContract] DataTable GetTbl(); } [OperationBehavior] public DataTable GetTbl(){ DataTable tbl = new DataTable("testTbl"); //Populate table with SQL query return tbl; } 

Inoltre, nel … Penso che la configurazione del servizio … vuoi specificare che gli errori possono essere inviati. È ansible che si stia verificando un errore che è simile al fatto che la dimensione del messaggio è troppo grande, ecc. È ansible correggerlo agendo sulle quote del lettore e così via.

Per impostazione predefinita wsHttpBinding ha una quota di dimensioni di ricezione pari a 65 KB, quindi se l’XML della tabella di dati serializzati è superiore a quello, genererebbe un errore (e sono sicuro al 95% che la tabella di dati sia più di 65 KB con i dati in essa contenuti ).

È ansible modificare le impostazioni per le quote del lettore e tali nel web.config / app.config oppure è ansible impostarlo su un’istanza di associazione nel codice. Ma sì, questo è probabilmente il tuo problema, se non lo hai cambiato per impostazione predefinita.

Membri WSHttpBindingBase : controlla la proprietà ReaderQuotas e la proprietà MaxReceivedMessageSize.

Probabilmente hai fatto saltare la tua quota – il datatable è più grande della dimensione massima consentita del pacchetto per la tua connessione.

Probabilmente hai bisogno di impostare MaxReceivedMessageSize e MaxBufferSize su valori più alti sulla tua connessione.

Ci sono 3 motivi per il tipo di datatable non riuscito come datatable nei servizi WCF

  • Devi specificare il nome della tabella dati come:

     MyTable=new DataTable("tableName"); 
  • Quando si aggiunge il riferimento sul lato client del servizio WCF, selezionare dll system.data riutilizzabile

  • Specificare l’attributo sulla variabile membro datatable come

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

Penso che Darren sia più probabile che sia corretto: i valori predefiniti forniti per WCF sono ridicoli e se ci si imbatte in essi si finisce con errori che possono essere difficili da rintracciare. Sembrano apparire non appena si tenta di fare qualcosa al di là di un semplice caso di test. Ho perso più tempo di quanto mi piacerebbe ammettere i problemi di debug che si sono rivelati correlati alle varie impostazioni di configurazione (dimensione) sia sul client che sul server. Penso di aver finito per modificare quasi tutti, es. MaxBufferPoolSize, MaxBufferSize, MaxConnections, MaxReceivedMessageSize, ecc.

Detto questo, l’utility SvcTraceViewer è anche indicata. Mi sono imbattuto in alcuni casi in cui non era così utile come avrei voluto, ma nel complesso è uno strumento utile per analizzare il stream delle comunicazioni e gli errori.