2010-07-30 7 views
23

Je reçois une erreur lorsque j'essaie stream.Length sur un objet Stream envoyé dans ma méthode WCF.Stream.Length déclenche NotSupportedException

Unhandled Exception! 
Error ID: 0 
Error Code: Unknown 
Is Warning: False 
Type: System.NotSupportedException 
Stack: at System.ServiceModel.Dispatcher.StreamFormatter.MessageBodyStream.get_Length() 

Comment obtenez-vous la longueur du flux? des exemples?

+0

La classe Stream est abstraite, ce qui est la classe Stream dérivé que vous utilisez? En outre, postez le code qui cause le problème si possible? –

Répondre

5

Vous ne pouvez pas toujours obtenir la longueur d'un flux. Dans le cas d'un flux réseau, le seul moyen de connaître la longueur est de lire les données jusqu'à ce qu'il soit fermé, par exemple.

Qu'essayez-vous de faire? Pourriez-vous lire le flux jusqu'à épuisement, en copiant les données dans un MemoryStream au fur et à mesure?

+0

J'ai juste besoin du nombre d'octets pour mettre à jour un compteur de perf. –

+4

@Nevin: Que se passe-t-il d'autre avec le flux? Fondamentalement, vous ne serez pas en mesure d'obtenir à cette information sans changer l'état en lisant à partir de lui. –

24

Stream.Length ne fonctionne que sur les implémentations de Stream où la recherche est disponible. Vous pouvez généralement vérifier si Stream.CanSeek est vrai. De nombreux flux, puisqu'ils sont en cours de diffusion , sont d'une nature où il est impossible de connaître la longueur à l'avance.

Si vous devez connaître la longueur, vous devrez peut-être réellement mettre en mémoire tampon le flux entier, en le chargeant à l'avance dans la mémoire.

+1

Qu'en est-il de 'HttpClient.GetStreamAsync (url)'? Il aura l'ensemble Longueur-propriété mais n'est pas recherché. Dois-je tester la valeur de l'attribut Stream.Length avec try-catch alors? –

4

Il n'est pas toujours possible d'obtenir la longueur d'un flux s'il ne supporte pas la recherche. Voir la table des exceptions sur le Stream class. Par exemple, un flux raccordé à un autre processus (flux réseau, sortie standard, etc.) peut produire une quantité quelconque de sortie, en fonction de la manière dont l'autre processus est écrit, et le framework ne peut pas comprendre comment beaucoup de données il y a.

Dans le cas général, il suffit de lire toutes les données jusqu'à la fin du flux, puis de déterminer combien vous avez lu.

0

TcpClient.EndRead() doit renvoyer le nombre d'octets qui se trouvent dans le flux.

--edit, bien sûr vous devez être en utilisant un flux TCP

6

j'ai rencontré ce même problème lors de l'utilisation des services WCF. J'avais besoin d'obtenir le contenu d'un message POST, et utilisais un argument Stream dans ma méthode pour obtenir le contenu du corps du message. Une fois que j'ai eu le flux, je voulais lire son contenu en une seule fois, et j'avais besoin de savoir de quel tableau d'octets de taille j'avais besoin. Donc, dans l'allocation du tableau, j'appellerais System.IO.Stream.Length et obtiendrais l'exception mentionnée par l'OP. Est-ce la raison pour laquelle vous devez connaître la longueur du flux afin que vous puissiez lire le contenu de l'ensemble du flux? Vous pouvez réellement lire tout le contenu du flux dans une chaîne à l'aide de System.IO.StreamReader. Si vous avez toujours besoin de connaître la taille de votre flux, vous pouvez obtenir la longueur de la chaîne résultante. Voici le code de la façon dont je l'ai résolu ce problème:

[OperationContract] 
    [WebInvoke(UriTemplate = "authorization")] 
    public Stream authorization(Stream body) 
    { 
     // Obtain the token from the body 
     StreamReader bodyReader = new StreamReader(body); 
     string bodyString= bodyReader.ReadToEnd(); 
     int length=bodyString.Length; // (If you still need this.) 
     // Do whatever you want to do with the body contents here. 
    } 
3

Voici ce que je fais:

// Return the length of a stream that does not have a usable Length property 
    public static long GetStreamLength(Stream stream) 
    { 
     long originalPosition = 0; 
     long totalBytesRead = 0; 

     if (stream.CanSeek) 
     { 
      originalPosition = stream.Position; 
      stream.Position = 0; 
     } 

     try 
     { 
      byte[] readBuffer = new byte[4096]; 

      int bytesRead; 

      while ((bytesRead = stream.Read(readBuffer, 0, 4096)) > 0) 
      { 
       totalBytesRead += bytesRead; 
      } 

     } 
     finally 
     { 
      if (stream.CanSeek) 
      { 
       stream.Position = originalPosition; 
      } 
     } 

     return totalBytesRead; 
    } 
+1

Avertissement: Utilisez le type 'long' pour' totalBytesRead' au cas où votre taille de fichier dépasserait 2 Go (~ 'int.MaxValue'). –