web-dev-qa-db-fra.com

Stream.Length lève une exception NotSupportedException

Je reçois une erreur lorsque j'essaie de stream.Length sur un objet Stream envoyé à ma méthode WCF.

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?

25
Nevin Mathai

Stream.Length ne fonctionne que sur les implémentations Stream où la recherche est disponible. Vous pouvez généralement vérifier si Stream.CanSeek est vrai. De nombreux flux, depuis qu'ils sont streamés, 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 mettre en mémoire tampon le flux entier en le chargeant préalablement dans la mémoire.

28
Reed Copsey

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 j'utilisais un argument Stream dans ma méthode pour obtenir le contenu du corps du message. Une fois que j'ai reçu le flux, je voulais en lire le contenu en une fois et je devais savoir quelle taille en octets il me faudrait. Donc, dans l'allocation du tableau, j'appellerais System.IO.Stream.Length et j'obtiendrais l'exception mentionnée par l'OP. La raison pour laquelle vous avez besoin de connaître la longueur du flux afin de pouvoir lire le contenu de l'ensemble du flux? Vous pouvez réellement lire le contenu entier du flux dans une chaîne en utilisant System.IO.StreamReader. Si vous avez encore besoin de connaître la taille de votre flux, vous pouvez obtenir la longueur de la chaîne résultante. Voici le code pour comment j'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. 
    }
9
froggythefrog

Vous ne pouvez pas toujours obtenir la longueur d'un flux. Dans le cas d'un flux de réseau, le seul moyen de déterminer la longueur consiste à lire les données de ce dernier jusqu'à sa fermeture, par exemple.

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

6
Jon Skeet

Il n'est pas toujours possible d'obtenir la longueur d'un flux s'il ne prend pas en charge la recherche. Voir le tableau des exceptions dans la classe Stream .

Par exemple, un flux connecté à un autre processus (flux réseau, sortie standard, etc.) peut produire toute quantité de sortie, en fonction de la manière dont l'autre processus est écrit, et le cadre ne dispose d'aucun moyen de déterminer la quantité de données qu'il contient. .

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

5
dsolimano

C'est 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;
    }
5
Paul Bartlett

TcpClient.EndRead () devrait renvoyer le nombre d'octets contenus dans le flux.

--Modifier, bien sûr, vous devez utiliser un flux TCP

0
daiglebagel