Question

J'ai un service WCF à partir duquel je souhaite renvoyer un DataTable.Je sais que c'est souvent un sujet très débattu, quant à savoir si le retour de DataTables est ou non une bonne pratique.Laissons cela de côté un instant.

Lorsque je crée un DataTable à partir de zéro, comme ci-dessous, il n'y a aucun problème.La table est créée, remplie et renvoyée au client, et tout va 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;
}

Cependant, dès que je sors et que j'accède à la base de données pour créer la table, comme ci-dessous, j'obtiens une exception CommunicationException "La connexion sous-jacente a été fermée :La connexion a été fermée de manière inattendue."

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

    return tbl;
}

Le tableau est correctement renseigné côté serveur.Elle est nettement plus petite que la table de test que j'ai parcourue et renvoyée, et la requête est petite et rapide - il n'y a aucun problème ici avec les délais d'attente ou le transfert de données volumineux.Les mêmes fonctions exactes et DataContracts/ServiceContracts/BehaviorContracts sont utilisées.

Pourquoi la façon dont la table est remplie aurait-elle une incidence sur le retour réussi de la table ?

Était-ce utile?

La solution

Pour tous ceux qui rencontrent des problèmes similaires, j'ai résolu mon problème.C'était multiple.

  • Comme Darren l'a suggéré et Paul l'a sauvegardé, les propriétés Max..Size dans la configuration devaient être agrandies.L'utilitaire SvcTraceViewer a aidé à déterminer cela, mais il ne donne toujours pas les messages d'erreur les plus utiles.
  • Il semble également que lorsque la référence de service est mise à jour côté client, la configuration ne se met parfois pas à jour correctement (par ex.La modification des valeurs de configuration sur le serveur ne sera pas toujours correctement mise à jour sur le client.J'ai dû modifier les propriétés Max..Size plusieurs fois côté client et côté serveur au cours de mon débogage)
  • Pour qu’un DataTable soit sérialisable, il faut lui donner un nom.Le constructeur par défaut ne donne pas de nom à la table, donc :

    return new DataTable();
    

    ne sera pas sérialisable, tandis que :

    return new DataTable("someName");
    

    nommera la table quel que soit le paramètre passé.

    Notez qu'une table peut recevoir un nom à tout moment en attribuant une chaîne au TableName propriété du DataTable.

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

J'espère que cela aidera quelqu'un.

Autres conseils

La meilleure façon de diagnostiquer ces types d’erreurs WCF (celles qui ne vous disent pas grand-chose) est d’activer le traçage.Dans votre fichier web.config, ajoutez ce qui suit :

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

Vous pouvez ensuite ouvrir le fichier résultant dans l'utilitaire SvcTraceViewer.exe fourni dans le SDK .NET Framework (ou avec Visual Studio).Sur ma machine, il se trouve dans %PROGRAMFILES%\Microsoft SDKs\Windows\v6.0A\Bin\SvcTraceViewer.exe.

Recherchez simplement un message d’erreur (en gras rouge) qui vous indiquera précisément quel est votre problème.

J'ai ajouté le Datable à un ensemble de données et j'ai renvoyé la table comme ceci...

DataTable result = new DataTable("result");

//linq to populate the table

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

J'espère que cela aide :)

Autre que la définition de valeurs maximales pour tous les attributs de liaison.

Assurez-vous que chaque table que vous transmettez/retournez depuis le service Web doit avoir un nom de table, c'est-à-dire le table.tablename la propriété ne doit pas être vide.

L'attribut souhaité est OperationContract (sur l'interface) / Operation Behaviour (sur la méthode) :

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


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

    return tbl;
}

Aussi, dans le...Je pense que la configuration du service...vous souhaitez préciser que des erreurs peuvent être envoyées.Vous rencontrez peut-être une erreur du type « la taille du message est trop grande, etc.Vous pouvez résoudre ce problème en manipulant les quotas de lecteurs, etc.

Par défaut, wsHttpBinding a un quota de taille de réception d'environ 65 Ko. Par conséquent, si le fichier XML de la table de données sérialisée est supérieur à cela, une erreur sera générée (et je suis sûr à 95 % que la table de données fait plus de 65 Ko et contient des données). ).

Vous pouvez modifier les paramètres des quotas de lecteurs et autres dans le web.config / app.config ou vous pouvez le définir sur une instance de liaison dans le code.Mais oui, c'est probablement là votre problème, si vous ne l'avez pas modifié par défaut.

Membres WSHttpBindingBase - Regardez la propriété ReaderQuotas ainsi que la propriété MaxReceivedMessageSize.

Vous avez probablement dépassé votre quota : la table de données est plus grande que la taille de paquet maximale autorisée pour votre connexion.

Vous devrez probablement définir Taille maximale du message reçu et Taille du tampon maximum à des valeurs plus élevées sur votre connexion.

Il y a 3 raisons pour lesquelles le type de retour a échoué : datatable dans les services WCF

  • Vous devez spécifier le nom de la table de données comme :

    MyTable=new DataTable("tableName");
    
  • Lorsque vous ajoutez une référence côté client du service WCF, sélectionnez une DLL réutilisable system.data

  • Spécifier l'attribut sur datatable variable membre comme

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

Je pense que Darren a probablement raison - les valeurs par défaut fournies pour WCF sont ridiculement petites et si vous les rencontrez, vous vous retrouvez avec des erreurs qui peuvent être difficiles à retrouver.Ils semblent apparaître dès que vous essayez de faire autre chose qu'un simple cas de test.J'ai perdu plus de temps que je ne voudrais l'admettre, des problèmes de débogage qui se sont avérés liés aux différents paramètres de configuration (taille) sur le client et le serveur.Je pense que j'ai fini par les modifier presque tous, ex.MaxBufferPoolSize, MaxBufferSize, MaxConnections, MaxReceivedMessageSize, etc.

Cela dit, l'utilitaire SvcTraceViewer également mentionné est génial.J'ai rencontré quelques cas où cela n'a pas été aussi utile que je l'aurais souhaité, mais dans l'ensemble, c'est un bon outil pour analyser le flux de communication et les erreurs.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top