Transfert de grandes charges utiles de données (objets sérialisés) en utilisant wsHttp dans WCF avec sécurité des messages

j'ai un cas où je dois transférer de grandes quantités de graphiques d'objets sérialisés (via NetDataContractSerializer) en utilisant WCF en utilisant wsHttp. J'utilise la sécurité des messages et j'aimerais continuer à le faire. En utilisant cette configuration, je voudrais transférer le graphe d'objet sérialisé qui peut parfois approcher environ 300MB mais quand j'essaie de le faire, j'ai commencé à voir une exception du système de type.L'insuffisance desmoryexceptions apparaît.

après un peu de recherche il apparaît que par défaut dans WCF qu'un résultat à un appel de service est contenu dans un message unique par défaut qui contient les données sérialisées et ces données sont amorties par défaut sur le serveur jusqu'à ce que le message entier est écrit. Ainsi, l'exception de mémoire est causée par le fait que le serveur est à court de ressources de mémoire qu'il est autorisé à allouer parce que cette mémoire tampon est pleine. Les deux principales recommandations que j'ai rencontré sont à utiliser en continu ou de segmentation de résoudre ce problème cependant, il n'est pas clair pour moi ce que cela implique et si l'une ou l'autre solution est possible avec ma configuration actuelle (Wshttp/NetDataContractSerializer/Message Security). Jusqu'à présent, je comprends que pour utiliser la sécurité des messages en continu ne fonctionnerait pas parce que le cryptage et le déchiffrement des messages doivent fonctionner sur l'ensemble des données et non un message partiel. Chunking cependant sonne comme il pourrait être possible, mais il n'est pas clair pour moi comment faire avec les autres contraintes qui J'ai énumérés. Si quelqu'un pouvait nous donner quelques conseils sur les solutions disponibles et sur la manière de les mettre en œuvre, je l'apprécierais beaucoup.

je dois ajouter que dans mon cas je ne suis pas vraiment inquiet de l'interopérabilité avec d'autres clients que nous possédons et de contrôler chaque côté de la communication et d'utiliser le modèle d'interface partagée pour les données transférées à l'un ou l'autre côté. Je suis donc ouvert à toute idée qui s'inscrit dans les contraintes de l'utilisation de wsHttp avec la sécurité des messages à transférer les graphiques d'objet sérialisé en utilisant NetDataContractSerializer et je préfère une solution où je n'ai pas à changer mes services existants et l'infrastructure environnante de façon drastique.

ressources Connexes:

je suis également intéressé par tout type de compression qui pourrait être fait sur ces données mais il semble que je serais probablement mieux de le faire au niveau du transport Une fois que je pourrai passer à .NET 4.0 afin que le client supporte automatiquement les en-têtes gzip si je comprends bien ceci correctement.

mise à Jour (2010-06-29):

un peu d'histoire sur la façon dont j'ai dérivé à la conclusion que le message tamponné étant trop grand causait mon problème. À l'origine, j'ai vu l' CommunicationException ci-dessous pendant les essais.

la connexion sous-jacente était fermée: la connexion était fermée de façon inattendue.

finalement après avoir lancé ceci et avoir fait plus de journalisation j'ai trouvé le sous-jacent InsufficientMemoryException exception qui causait le problème avec le message spécifié.

échec d'allouer un tampon mémoire géré de 268435456 octets. La quantité de mémoire disponible peut être faible.

origine de la méthode suivante.

Système.ServiceModel.Diagnostic.Utilitaire.AllocateByteArray (Int32 size)

donc en d'autres mots l'échec vient de l'allocation du tableau. En écrivant la même série de données au disque il prend environ 146MB et si je le coupe de moitié alors j'arrête d'obtenir l'erreur cependant je n'ai pas creusé beaucoup plus dans le seuil spécifique qui casse mon tampon et si elle spécifique à mon système ou non.

mise à Jour (2010-12-06):

je suppose qu'à ce stade, je cherche des clarifications pour ce qui suit. Ma compréhension est que par défaut avec WCF wsHttp avec la sécurité de message qu'un message Entier (Généralement le tout l'ensemble des données que je retourne) doit être tamponné sur le serveur avant que la réponse soit envoyée au client et donc causer mes problèmes.

solutions possibles:

  • limiter la taille des données - en utilisant une certaine forme de compression, d'encodage, ou de limitation des données réelles retournées en utilisant une sorte de méthode de pagination afin d'éviter de consommer la capacité maximale du tampon sortant.
  • Streaming-permet d'envoyer de grandes quantités de données grâce à WCF en mode streaming cependant ceci n'est pas compatible avec wsHttp ou MessageSecurity puisque ces techniques nécessitent la mise en mémoire tampon de toutes les données.
  • Chunking Channel-Permet de décomposer les données en messages séparés mais à ce stade Je ne suis pas sûr des contraintes que cela a sur la conception du contrat de service et si je peux encore utiliser wsHttp avec la liaison de message.

limiter les données que je peux retourner ne fonctionne que jusqu'à un point et comme avec le Streaming option ces options exigent le codage d'une grande partie du travail de niveau inférieur en dehors des appels de service de la FMC. Donc, je suppose que ce que je dois savoir est de savoir si une éventuelle mise en œuvre du canal de chunking peut éviter les problèmes de grands messages en permettant à un seul ensemble de données d'être décomposé en messages séparés sur le serveur, puis assemblé sur le client de telle manière que je n'ai pas à changer l'interface / forme des contrats de services existants et d'une manière que le processus est à peu près beaucoup caché de la partie client et serveur de chaque implémentation de service tout en utilisant la sécurité des messages et wsHttp. Si le chunking-channel va me demander de réécrire mes contrats de service pour exposer les flux alors je ne vois pas en quoi c'est vraiment différent de la solution de Streaming. Si quelqu'un peut simplement répondre à ces questions pour moi, je lui accorderai la prime et la marquerai comme réponse.

16
demandé sur jpierson 2010-06-10 20:39:01

5 réponses

protobuf-net a généralement un important économie d'espace (comme dans: ordre de grandeur) sur la plupart des données, et peut se rattacher à la FMC. Malheureusement pour le moment il ne supporte pas les graphiques complets, seulement les arbres. Cependant, j'ai plans là que je n'ai tout simplement pas eu le temps de mettre en place. Je ne peux rien promettre, mais je peux essayer de faire ce travail un peu plus tôt.

autrement; il peut y avoir des façons de modifier votre code existant pour travailler avec un arbre à la place d'un graphe.

3
répondu Marc Gravell 2010-12-04 10:40:44

si vous souhaitez toujours utiliser la sécurité des messages, je vous recommande D'utiliser MTOM pour optimiser la bande passante réseau qui doit être utilisée pour transférer les messages, et aussi le canal de chunking pour utiliser des tampons mémoire plus petits lorsque la sécurité est appliquée. Sinon, WCF va essayer de charger le message entier en mémoire pour appliquer la sécurité, et donc vous obtiendrez L'exception mémoire insuffisante.

2
répondu pablo cibraro 2010-06-30 14:31:34

j'avais l'habitude de mettre en place un genre de passage de gros texte de/vers la wcf. mon trig est le convertir en flux et utiliser GZipStream pour le compresser puis l'envoyer comme byte [], heureusement son ne dépasse jamais 10 MB.

psudo

int transferSize = 5000000; // 5MB
byte[] compressed = ...;
var mem = new System.IO.MemoryStream(compressed);

for(int i = 0; i < compressed .length; i+= transferSize )
{
    byte[] buffer = new byte[transferSize];
    mem.Read(buffer, i, compressed);
    mem.Flush();
    sendFragmentToWCF(buffer);
}

modifier le 08 Déc 2010

OK d'après ce que j'ai compris, la situation est que le client est en train de télécharger un gros objet serialize au travers de la WCF. Je n'ai pas testé cette solution, mais ça devrait marcher. La clé est de sauvegarder l'objet sérialisé pour le fichier et d'utiliser la réponse transmettre ce fichier.

[WebMethod]
public void GetSerializedObject()
{
    string path = @"X:\temp.tmp";

    var serializer = new  System.Runtime.Serialization.NetDataContractSerializer();
    var file = new System.IO.FileStream(path, System.IO.FileMode.CreateNew);

    try
    {
        serializer.Serialize(file, ...);
        this.Context.Response.TransmitFile(path);
        this.Context.Response.Flush();
    }
    finally
    {
        file.Flush();
        file.Close();
        file.Dispose();
        System.IO.File.Delete(path);
    }
}

WCF shoud faire le streaming de fichier automatiquement et U dont ahve de se soucier de la taille de l'objet sérialisé puisque nous utilisons le fichier transmettre. N'oubliez pas la limite de réponse de la configuration.

2
répondu Bonshington 2012-04-26 21:12:35

des solutions plus légères, mais non garanties, seraient

  • DataContractSerializer au lieu de cela puisque vous possédez les deux côtés. Cela ne nécessite pas d'informations de type intégré, qui est de grande taille.
  • utiliser [DataMember(EmitDefaultValue = false)] ce qui est discuté dans une question, j'ai demandé - encore une fois parce que vous possédez les deux côtés; faire ainsi va réduire certains sur la taille du message (combien dépend bien sûr de combien de champs dans le graphique sont par défaut).
  • utiliser [DataContract(IsReference=true)], surtout si vous avez beaucoup d'objets de valeur répétés ou de données de référence
  • utilisez une sorte d'étranglement sur le serveur pour réduire la pression mémoire des résultats simultanés

ce sont, bien sûr, des compromis, par exemple avec la lisibilité.

0
répondu Kit 2017-05-23 11:45:38

puisque personne ne l'a mis dehors, peut-être en utilisant WebSockets ou sondage de longue durée

l'idée sous-jacente serait de réaliser quelque chose de similaire à la façon dont l'idée de L'exemple ChunkingChannel fonctionne, mais sans exiger un canal duplex complet qui casse typiquement le port 80 web basé sur le modèle de requête/réponse qui est souhaitable pour éviter d'avoir à faire pare-feu et autres configurations connexes pour les clients.

Autres:

mise à jour: après des recherches plus sur ce sujet, il semble qu'en utilisant WebSockets, qui est connu connu sous le nom de NetHttpBinding, que je ne serais pas intrinsèquement résoudre la requête originale qui est d'utiliser wsHttp dans WCF avec la sécurité de message. Je vais garder ma réponse ici cependant comme information pour d'autres qui peuvent être à la recherche d'une alternative.

0
répondu jpierson 2013-01-30 18:31:59