Domanda

Ho un servizio WCF da cui desidero restituire un DataTable.So che questo è spesso un argomento molto dibattuto, per quanto riguarda se restituire DataTables sia o meno una buona pratica.Mettiamolo 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 premo il database per creare la tabella, come di seguito, ottengo una CommunicationException "La connessione sottostante è stata chiusa:La connessione è stata chiusa inaspettatamente."

[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ù piccola della tabella di test che ho eseguito in loop e restituito e la query è piccola e veloce: qui non ci sono problemi con timeout o trasferimenti di dati di grandi dimensioni.Vengono utilizzate le stesse identiche funzioni e DataContracts/ServiceContracts/BehaviorContracts.

Perché il modo in cui la tabella viene popolata dovrebbe avere qualche influenza sulla restituzione della tabella con successo?

È stato utile?

Soluzione

Per chiunque abbia problemi simili, ho risolto il mio problema.È stato molteplice.

  • Come suggerito da Darren e sostenuto da Paul, le proprietà Max..Size nella configurazione dovevano essere ingrandite.L'utilità SvcTraceViewer ha aiutato a determinarlo, ma non sempre fornisce i messaggi di errore più utili.
  • Sembra inoltre che quando il riferimento al servizio viene aggiornato sul lato client, la configurazione a volte non si aggiorna correttamente (ad es.La modifica dei valori di configurazione sul server non verrà sempre aggiornata correttamente sul client.Ho dovuto entrare e modificare le proprietà Max..Size più volte sia sul lato client che sul lato server nel corso del mio debug)
  • Affinché un DataTable sia serializzabile, è necessario assegnargli un nome.Il costruttore predefinito non assegna un nome alla tabella, quindi:

    return new DataTable();
    

    non sarà serializzabile, mentre:

    return new DataTable("someName");
    

    nominerà la tabella qualunque cosa venga passata come parametro.

    Tieni presente che è possibile assegnare un nome a una tabella in qualsiasi momento assegnando una stringa al file TableName proprietà del DataTable.

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

Spero che questo possa aiutare qualcuno.

Altri suggerimenti

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

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

È quindi possibile aprire il file risultante nell'utilità SvcTraceViewer.exe fornita in .NET Framework SDK (o con Visual Studio).Sul mio computer, è disponibile in %PROGRAMFILES%\Microsoft SDKs\Windows\v6.0A\Bin\SvcTraceViewer.exe.

Cerca semplicemente un messaggio di errore (in grassetto rosso) che ti dirà specificamente qual è il tuo problema.

Ho aggiunto 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 :)

Oltre all'impostazione di valori massimi per tutti gli attributi di associazione.

Assicurati che ogni tabella che stai passando/restituisci dal servizio web deve avere un nome di tabella, ovvero il table.tablename la proprietà non deve essere vuota.

L'attributo desiderato è OperationContract (sull'interfaccia)/Operation Behavior (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...si desidera specificare che possono essere inviati errori.Potresti riscontrare un errore simile a quello in cui la dimensione del messaggio è troppo grande, ecc.Puoi risolverlo modificando le quote dei lettori e simili.

Per impostazione predefinita, wsHttpBinding ha una quota di dimensione di ricezione pari a 65 KB, quindi se l'XML della tabella dati serializzata è superiore, verrà generato un errore (e sono sicuro al 95% che la tabella dati contenga più di 65 KB con dati) ).

Puoi modificare le impostazioni per le quote di lettura e simili nel file web.config / app.config oppure puoi impostarlo su un'istanza di associazione nel codice.Ma sì, probabilmente è questo il tuo problema, se non l'hai modificato per impostazione predefinita.

Membri WSHttpBindingBase - Guarda la proprietà ReaderQuotas e la proprietà MaxReceivedMessageSize.

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

Probabilmente è necessario impostare Dimensione massima messaggio ricevuto E Dimensione buffer massima a valori più alti sulla tua connessione.

Esistono 3 motivi per il tipo di reso non riuscito come datatable nei servizi WCF

  • Devi specificare il nome della tabella dati come:

    MyTable=new DataTable("tableName");
    
  • Quando aggiungi un riferimento sul lato client del servizio WCF, seleziona DLL riutilizzabile system.data

  • Specificare l'attributo attivo datatable variabile membro come

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

Penso che Darren abbia molto probabilmente ragione: i valori predefiniti forniti per WCF sono ridicolmente piccoli e se li incontri ti ritroverai con errori che possono essere difficili da rintracciare.Sembrano apparire non appena si tenta di fare qualcosa che vada oltre un semplice caso di prova.Ho perso più tempo di quanto vorrei ammettere risolvendo problemi che si sono rivelati correlati alle varie impostazioni di configurazione (dimensioni) sia sul client che sul server.Penso di aver finito per modificarli quasi tutti, es.MaxBufferPoolSize, MaxBufferSize, MaxConnections, MaxReceivedMessageSize, ecc.

Detto questo, anche l'utilità SvcTraceViewer menzionata è fantastica.Mi sono imbattuto in alcuni casi in cui non è stato utile come avrei voluto, ma nel complesso è uno strumento utile per analizzare il flusso delle comunicazioni e gli errori.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top