Stream.Length throws NotSupportedException
Asked Answered
B

7

37

I am getting a error when attempting stream.Length on a Stream object sent into my WCF method.

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

How do you get the length of the stream? any examples?

Benedix answered 30/7, 2010 at 16:41 Comment(1)
The Stream class is abstract, what's the derived Stream class you are using? Also, post the code that's causing the issue if possible?Betjeman
R
41

Stream.Length only works on Stream implementations where seeking is available. You can usually check to see if Stream.CanSeek is true. Many streams, since they're being streamed, are of a nature where it's impossible to know the length in advance.

If you must know the length, you may need to actually buffer the entire stream, loading it into memory in advance.

Rusert answered 30/7, 2010 at 16:46 Comment(2)
What's about HttpClient.GetStreamAsync(url)? It will have the Length-property set but is not seekable. Do I have to test the value of the Stream.Length attribute with try-catch then?Eldoree
@BrunoZell In the case of HTTP request/response streams: the Content-Length header cannot be trusted ("never trust the [client|other end of the pipe]!"): the connection could be aborted or the server may push more data down the TCP connection than the client expects.Lexie
R
14

This is what I do:

// 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;
}
Roentgen answered 8/1, 2014 at 8:41 Comment(1)
Caveat: Use type long for totalBytesRead in case your file size might exceed 2 GB (~ int.MaxValue).Kimberykimble
A
12

I encountered this same problem when using WCF services. I needed to get the contents of a POST message, and was using a Stream argument in my method to get the contents of the message's body. Once I got the stream, I wanted to read its contents all at once, and needed to know what size byte array I would need. So, in the allocation of the array, I would call System.IO.Stream.Length and get the exception mentioned by the OP. Is the reason you need to know the length of the stream so that you can read the contents of the entire stream?

You can actually read the entire contents of the stream into a string using System.IO.StreamReader. If you still need to know the size of your stream, you can get the length of the resulting string. Here's the code for how I solved this problem:

    [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. 
    }
Arlindaarline answered 21/10, 2012 at 0:5 Comment(0)
E
7

You can't always get the length of a stream. In the case of a network stream, the only way of finding out the length is to read data from it until it's closed, for example.

What are you trying to do? Could you read from the stream until it's exhausted, copying the data into a MemoryStream as you go?

Ewart answered 30/7, 2010 at 16:45 Comment(1)
@Nevin: What else is happening with the stream? Basically you won't be able to get at this information without changing the state by reading from it.Ewart
C
6

It is not always possible to get the length of a stream if it doesn't support seeking. See the exception table on the Stream class.

For example, a stream hooked up to another process (network stream, standard output, etc) can produce any amount of output, depending on how the other process is written, and there's no way for the framework to figure out how much data there is.

In the general case, you just have to read in all of the data until the end of the stream and then figure out how much you've read.

Courante answered 30/7, 2010 at 16:47 Comment(0)
E
0

TcpClient.EndRead() should return the number of bytes that are in the stream.

--Edit, of course you need to be using a TCP Stream

Elaineelam answered 30/7, 2010 at 16:49 Comment(0)
R
0

I copied the stream into new stream and it worked for me.

Stream stream = new MemoryStream();
await streamthatcausingerror.CopyToAsync(stream); 

Resorcinol answered 5/5, 2022 at 0:57 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.