views:

504

answers:

2

I'm in the process of creating a custom stream for an API endpoint in my app. The stream needs to have custom logic that I don't want to get into, but suffice to say I can't use a built-in stream class.

I did the minimum necessary to implement a read-only stream (inheriting from System.IO.Stream) and I've verified that the System.IO.BinaryReader class can read from my stream:

Dim reader As New System.IO.BinaryReader(GenerateStream(business, logic))
Dim enc As New System.Text.ASCIIEncoding
Dim contents As String = enc.GetString(reader.ReadBytes(CType(reader.BaseStream.Length, Int32)))

The string "contents" contains the correct string for the entire stream.

However, I would like to be able allow the use of the System.IO.StreamReader class:

Dim reader As New System.IO.StreamReader(GenerateStream(business, logic), System.Text.Encoding.ASCII)
Dim contents As String = reader.ReadToEnd

but for whatever reason the ReadToEnd always returns the empty string.

Any ideas?

Here's the stream:

Public Overrides ReadOnly Property CanRead() As Boolean
   Get
    Return True
   End Get
  End Property

  Public Overrides ReadOnly Property CanSeek() As Boolean
   Get
    Return False
   End Get
  End Property

  Public Overrides ReadOnly Property CanWrite() As Boolean
   Get
    Return False
   End Get
  End Property

  Public Overrides Sub Flush()
   'this method intentionally left blank'
  End Sub

  Public Overrides ReadOnly Property Length() As Long
   Get
    Return 'some business logic'
   End Get
  End Property

  Public Overrides Property Position() As Long
   Get
    Return bytePosition
   End Get
   Set(ByVal value As Long)
    Throw New System.NotSupportedException
   End Set
  End Property

  Public Overrides Function Read(ByVal buffer() As Byte, ByVal offset As Integer, ByVal count As Integer) As Integer
   'I return 0 on an end of stream, otherwise the # of bytes successfully read.'
  End Function

  Public Overrides Function Seek(ByVal offset As Long, ByVal origin As System.IO.SeekOrigin) As Long
   Throw New System.NotSupportedException
  End Function

  Public Overrides Sub SetLength(ByVal value As Long)
   Throw New System.NotSupportedException()
  End Sub

  Public Overrides Sub Write(ByVal buffer() As Byte, ByVal offset As Integer, ByVal count As Integer)
   Throw New System.NotSupportedException()
  End Sub
A: 

Try doing this:

Dim reader As New System.IO.StreamReader(
    GenerateStream(business, logic), 
    System.Text.Encoding.ASCII, 
    False
)
Dim contents As String = reader.ReadToEnd

Also make sure all the methods you don't want used will throw NotImplementedException.

ChaosPandion
They're throwing NotSupportedExceptions like System.IO.Stream warns can happen. Are you sure that you don't mean NotSupportedException instead of NotImplementedException?
Evan Larkin
@Evan - It actually doesn't matter. The reason I recommend this is because if the Stream Reader calls these methods expecting something to happen it will throw and thus make your debugging easier.
ChaosPandion
A: 
Abel
The data is characters (in this case encoded in ascii). I haven't tried reading past the end of the stream with the BinaryReader, but I have verified that you can read /to/ the end with a BinaryReader and you get the correct output.Although perhaps if I implement seeking the problem will just go away. I did miss the description of "ReadToEnd" though. If seeking fixes the problem, this is the answer.A BinaryReader implementation of ReadToEnd is displayed in the question.
Evan Larkin
The problem did lie in my read method. My read method would return 0 if the /current/ read reached the end of the stream. It now returns 0 only if reading from an empty stream.
Evan Larkin
No, seeking or not seeking is not an issue. As you've found out, your interface implementation must be correct. It's hard to help with finding such error without seeing all relevant code... ;)
Abel