Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 7 years ago.
Improve this question
I have an input stream and a stream reader component. This works fine but now I want to log all the traffic (save a copy in a file).
So I need to spy on a stream. A solution I am thinking of is a stream pipe (pipeline) or a stream wrapper that takes a stream as input and then gives me a first look at the traffic. Something like this:
void Init(System.Net.Sockets.NetworkStream stream)
{
System.IO.Stream wrappedStream = new MyWrapper(stream);
wrappedStream.ReadSpy = MyMethod;
XmlReader reader = XmlReader.Create(wrappedStream);
}
// This will get called after some bytes have been read from a stream,
// but before they get passed to the XmlReader
byte[] MyMethod(byte[] buffer)
{
m_Writer.Write(buffer); // write to a file
return buffer; // Give to XmlReader
}
What you want is called the Decorator Pattern. It's a technique for dynamically adding/modifying behavior:
http://sourcemaking.com/design_patterns/decorator
http://www.oodesign.com/decorator-pattern.html
To do this, you want to implement the abstract class Stream, with a constructor of factory that accepts another Stream instance. You provide an implementation for every method/overload of the abstract class that invokes the same method/overload on the decorated Stream, plus doing whatever additional work your needs require.
Once you've done that and decorated a Stream with your new decorator, It can be used interchangeably by anything else that accepts a Stream, including other similar decorators: decorators can even be nested, like layers of an onion to compose the behaviors you need.
Something like this:
class StreamInterceptor : Stream
{
public Stream DecoratedInstance { get; set; }
public event Action<byte[]> BytesRead;
public event Action<byte[]> BytesWritten;
public StreamInterceptor( Stream instance )
{
if ( instance == null ) throw new ArgumentNullException("instance");
this.DecoratedInstance = instance ;
return ;
}
public override bool CanRead
{
get { return DecoratedInstance.CanRead; }
}
public override bool CanSeek
{
get { return DecoratedInstance.CanSeek; }
}
public override bool CanWrite
{
get { return DecoratedInstance.CanWrite; }
}
public override void Flush()
{
DecoratedInstance.Flush();
return;
}
public override long Length
{
get { return DecoratedInstance.Length; }
}
public override long Position
{
get { return DecoratedInstance.Position; }
set { DecoratedInstance.Position = value; }
}
public override int Read( byte[] buffer , int offset , int count )
{
int bytesRead = DecoratedInstance.Read(buffer, offset, count);
// raise the bytes read event
byte[] temp = new byte[bytesRead];
Array.Copy(buffer,offset,temp,0,bytesRead);
BytesRead(temp);
return bytesRead;
}
public override long Seek( long offset , SeekOrigin origin )
{
return DecoratedInstance.Seek(offset, origin);
}
public override void SetLength( long value )
{
DecoratedInstance.SetLength(value);
return;
}
public override void Write( byte[] buffer , int offset , int count )
{
// raise the bytes written event
byte[] temp = new byte[count];
Array.Copy(buffer,offset,temp,0,count);
BytesWritten(temp);
DecoratedInstance.Write(buffer, offset, count);
return;
}
}
Once you have that, you can say something like this:
static void Main()
{
StreamInterceptor si = new StreamInterceptor(File.Open("foo.bar.txt",FileMode.Open,FileAccess.ReadWrite,FileShare.Read));
si.BytesRead += (bytes) => { Console.WriteLine("{0} bytes read", bytes.Length); } ;
si.BytesWritten += (bytes) => { Console.WriteLine("{0} bytes written", bytes.Length); } ;
Stream s = (Stream) si ;
DoSomethingUseful(s);
}
And your event handler will be invoked whenever somebody reads or writes from the stream.
Related
I am using StreamReader over NetworkStream and I want just read one or more lines and another data is byte array (like file data) and I dont want to read that file data in StreamReader, for example I need to read text header line by line and when I see one empty line, header reads must end and next I must read bytes of file,
When I test this with StreamReader I get problems because StreamReader read bytes before I calling ReadLine (after first ReadLine) and after dispose StreamReader and using NetworkStream to read bytes I get block of bytes that is not start of file byte array after header, because StreamReader readed block of bytes in ReadLine and not called ReadLine.
What is wrong in StreamReader or my code settings?
using (var reader = new StreamReader(tcpClient.GetStream()))
{
while (true)
{
var line = reader.ReadLine();
headerResponse += line + "\r\n";
if (line == "")
break;
}
using (var fileStreamReader = tcpClient.GetStream())
{
byte[] bytes = new byte[1024];
var readCount = fileStreamReader.Read(bytes, 0, bytes.Length);
}
}
I created one CustomStreamReader and I read bytes one by one in ReadLine Method and fixed my problem:
public class CustomStreamReader : Stream
{
NetworkStream CurrentStream { get; set; }
public CustomStreamReader(NetworkStream currentStream)
{
CurrentStream = currentStream;
}
public override bool CanRead => CurrentStream.CanRead;
public override bool CanSeek => CurrentStream.CanSeek;
public override bool CanWrite => CurrentStream.CanWrite;
public override long Length => CurrentStream.Length;
public override long Position { get => CurrentStream.Position; set => CurrentStream.Position = value; }
public override void Flush()
{
CurrentStream.Flush();
}
public override int Read(byte[] buffer, int offset, int count)
{
return CurrentStream.Read(buffer, offset, count);
}
public override long Seek(long offset, SeekOrigin origin)
{
return CurrentStream.Seek(offset, origin);
}
public override void SetLength(long value)
{
CurrentStream.SetLength(value);
}
public override void Write(byte[] buffer, int offset, int count)
{
CurrentStream.Write(buffer, offset, count);
}
public string ReadLine()
{
List<byte> result = new List<byte>();
do
{
int data = CurrentStream.ReadByte();
if (data == -1)
break;
result.Add((byte)data);
if (data == 13)
{
data = CurrentStream.ReadByte();
if (data == -1)
break;
result.Add((byte)data);
if (data == 10)
break;
}
}
while (true);
return Encoding.UTF8.GetString(result.ToArray());
}
}
My goal is to read from one stream, transform that stream, and use it as an input to a library that accepts a Stream to read.
I am using two different libraries. One takes an output Stream and transforms it. Let's call it TransformingOutputStream. Its intended use is:
var outputStream = new TransformingOutputStream(finalDestinationOutputStream);
inputStream.CopyTo(outputStream);
I'm using another library that accepts an input Stream. It does whatever it needs and then reads from that stream. Its intended use is:
MagicStreamReadingLibrary.ProcessStream(someInputStream);
I can't pass TransformingOutputStream to it because its intended use is to be written-to, not read-from. I do not have control over either library.
How do I hook-up the TransformingOutputStream to the library function that requires reading from an input Stream?
So far this is the best working example I have, using Anonymous Pipes:
using( var pipeServer = new AnonymousPipeServerStream( PipeDirection.Out ) ) {
var pipeServerTask = Task.Run(
async () => {
using( var stream = getInputStream() ) {
await stream.CopyToAsync( new TransformingOutputStream( pipeServer ) );
}
pipeServer.WaitForPipeDrain();
pipeServer.Dispose();
} );
using( var client = new AnonymousPipeClientStream( PipeDirection.In, pipeServer.ClientSafePipeHandle ) ) {
MagicStreamReadingLibrary.ProcessStream( client );
}
pipeServerTask.Wait();
}
Write it to a flat file then read it back out.
Here is something I just threw together, it should in theory work (untested, I just know it compiles correctly).
public class BufferingStream
{
private readonly Stream _readingStream;
private readonly Stream _writingStream;
private BlockingCollection<byte[]> _buffer;
public BufferingStream()
{
_buffer = new BlockingCollection<byte[]>(new ConcurrentQueue<byte[]>());
_readingStream = new InternalReadingStream(_buffer);
_writingStream = new InternalWritingStream(_buffer);
}
public BufferingStream(int maxQueueLength)
{
_buffer = new BlockingCollection<byte[]>(new ConcurrentQueue<byte[]>(), maxQueueLength);
_readingStream = new InternalReadingStream(_buffer);
_writingStream = new InternalWritingStream(_buffer);
}
public Stream GetReadingStream()
{
return _readingStream;
}
public Stream GetWritingStream()
{
return _writingStream;
}
public int QueueLength
{
get { return _buffer.Count; }
}
public class InternalWritingStream : Stream
{
private readonly BlockingCollection<byte[]> _queuedBytes;
public InternalWritingStream(BlockingCollection<byte[]> queuedBytes)
{
_queuedBytes = queuedBytes;
}
public override void Write(byte[] buffer, int offset, int count)
{
byte[] internalBuffer = new byte[count];
Array.Copy(buffer, offset, internalBuffer, 0, count);
_queuedBytes.Add(internalBuffer);
}
public override void Close()
{
_queuedBytes.CompleteAdding();
base.Close();
}
public override void Flush()
{
}
public override long Seek(long offset, SeekOrigin origin)
{
throw new NotSupportedException();
}
public override void SetLength(long value)
{
throw new NotSupportedException();
}
public override int Read(byte[] buffer, int offset, int count)
{
throw new NotSupportedException();
}
public override bool CanRead
{
get { return false; }
}
public override bool CanSeek
{
get { return false; }
}
public override bool CanWrite
{
get { return true; }
}
public override long Length
{
get { throw new NotSupportedException(); }
}
public override long Position
{
get { throw new NotSupportedException(); }
set { throw new NotSupportedException(); }
}
}
private sealed class InternalReadingStream : Stream
{
private readonly BlockingCollection<byte[]> _queuedBytes;
private byte[] _currentItem;
private int _currentItemOffset;
public InternalReadingStream(BlockingCollection<byte[]> queuedBytes)
{
_queuedBytes = queuedBytes;
_currentItem = new byte[0];
_currentItemOffset = 0;
}
public override int Read(byte[] buffer, int offset, int count)
{
if (_currentItemOffset == _currentItem.Length)
{
//Try to take the next buffer, if we can't take a item it means we where done adding from the source.
var taken = _queuedBytes.TryTake(out _currentItem, Timeout.Infinite);
if (!taken)
return 0;
_currentItemOffset = 0;
}
var bytesToRead = Math.Min(count, _currentItem.Length - _currentItemOffset);
Array.Copy(_currentItem, _currentItemOffset, buffer, offset, bytesToRead);
_currentItemOffset += bytesToRead;
return bytesToRead;
}
public override void Flush()
{
}
public override long Seek(long offset, SeekOrigin origin)
{
throw new NotSupportedException();
}
public override void SetLength(long value)
{
throw new NotSupportedException();
}
public override void Write(byte[] buffer, int offset, int count)
{
throw new NotSupportedException();
}
public override bool CanRead
{
get { return true; }
}
public override bool CanSeek
{
get { return false; }
}
public override bool CanWrite
{
get { return false; }
}
public override long Length
{
get { throw new NotSupportedException(); }
}
public override long Position
{
get { throw new NotSupportedException(); }
set { throw new NotSupportedException(); }
}
}
}
The way it would work in your use case would be
var bufferingStream = new BufferingStream();
Task.Run(() =>
{
using(var inputStream = GetTheStreamFromSomewhere();
using(var finalDestinationOutputStream = bufferingStream.GetWritingStream())
using(var outputStream = new TransformingOutputStream(finalDestinationOutputStream))
{
inputStream.CopyTo(outputStream);
}
}
using(var someInputStream = bufferingStream.GetReadingStream()) //Technically a using is not necessary on the reading stream but it is good to keep good habits.
{
MagicStreamReadingLibrary.ProcessStream(someInputStream);
}
Initially calls to .Read( calls ProcessStream makes will block until data becomes available. As bytes become available .Read( unblocks and passes along the data. Once finalDestinationOutputStream is disposed it will mark the queue as completed adding and once outputStream finishes its last read it will just return 0 for any subsequent calls.
If you find that your writer is much faster than your reader you may want to pass in a max queue length so writes will block till the reader has a chance to read.
I'm building a server / client application and I'm looking through options for separating packets. I've read that the most proper one would be creating a header that contains information on how big the payload is and then read until it ends.
How does that programmatically works?
Also separating those by using "\n" newline. A proper example would be nice.
I'm async receiving data this way:
private void AsyncReceive(IAsyncResult result)
{
int bytesTransfered;
try
{
bytesTransfered = _handle.EndReceive(result);
if(bytesTransfered <= 0)
{
throw new Exception("No bytes transfered");
}
}
catch(NullReferenceException)
{
return;
}
catch(ObjectDisposedException)
{
return;
}
catch(Exception)
{
return;
}
byte[] received = new byte[bytesTransfered];
try
{
Array.Copy(_readBuffer, received, received.Length);
}
catch(Exception)
{
Disconnect();
return;
}
// How should I process the received data now?
try
{
_handle.BeginReceive(_readBuffer, 0, _readBuffer.Length, SocketFlags.None, AsyncReceive, null);
}
catch(ObjectDisposedException)
{
return;
}
catch(Exception)
{
}
}
First you need to distinguish between different types of messages. You can use single byte for that, which will allow for up to 255 different message types. Make an enum for that, and an attribute to mark your messages (see below):
enum MessageType : byte {
FirstMessage,
SecondMessage
}
class MessageAttribute : Attribute {
public MessageAttribute(MessageType type) {
Type = type;
}
public MessageType Type { get; private set; }
}
Second, you need compact serializer for your messages. One good option is protobuf - it it's very compact (does not serialize property names, only values and so on) while still easy to use.
[Message(MessageType.FirstMessage)]
[ProtoContract]
class MyFirstMessage {
[ProtoMember(1)]
public string Value { get; set; }
[ProtoMember(2)]
public int AnotherValue { get; set; }
}
[Message(MessageType.SecondMessage)]
[ProtoContract]
class MySecondMessage {
[ProtoMember(1)]
public decimal Stuff { get; set; }
}
Third you need to know the length of a message, as caller says you. Use 2 or 4 bytes for that (size of Int16 and Int32 types respectively).
So our format would be: 1 byte - message type. 2-5 bytes - message size, 5-5+size bytes - protobuf serialized message. Then read your stream in three steps, as defined below:
class MessageReader {
static readonly Dictionary<byte, Type> _typesMap = new Dictionary<byte, Type>();
static MessageReader() {
// initialize your map
// this is executed only once per lifetime of your app
foreach (var type in Assembly.GetExecutingAssembly().GetTypes().Where(c => c.GetCustomAttribute<MessageAttribute>() != null)) {
var message = type.GetCustomAttribute<MessageAttribute>();
_typesMap.Add((byte)message.Type, type);
}
}
public async Task<object> Read(Stream stream) {
// this is your network or any other stream you have
// read first byte - that is message type
var firstBuf = new byte[1];
if (await stream.ReadAsync(firstBuf, 0, 1) != 1) {
// failed to read - end of stream
return null;
}
var type = firstBuf[0];
if (!_typesMap.ContainsKey(type)) {
// unknown message, handle somehow
return null;
}
// read next 4 bytes - length of a message
var lengthBuf = new byte[4];
if (await stream.ReadAsync(lengthBuf, 0, 4) != 4) {
// read less than expected - EOF
return null;
}
var length = BitConverter.ToInt32(lengthBuf, 0);
// check if length is not too big here! or use 2 bytes for length if your messages allow that
if (length > 1*1024*1024) {
// for example - adjust to your needs
return null;
}
var messageBuf = new byte[length];
if (await stream.ReadAsync(messageBuf, 0, length) != length) {
// didn't read full message - EOF
return null;
}
try {
return ProtoBuf.Serializer.NonGeneric.Deserialize(_typesMap[type], new MemoryStream(messageBuf));
}
catch {
// handle invalid message somehow
return null;
}
}
}
After you read one message from stream - continue in the same way to read next message. Read calls will block until new data arrives. If there is any violation of protocol - drop connection.
Have you not considered using a TCPClient and TCPListener, and then a NetworkStream? Sockets are pretty low level and probably not needed in the majority of cases.
See this post:
How reading messages from server?(TCP)
Also, do not catch exceptions that you cannot recover from, unless you log and rethrow them. This will cause very hard to debug behaviors when exceptions get silently swallowed up.
I have a non-closing stream class that's wrapped in a using block with a binary reader, but for some reason when the block ends, my non-closing stream still closes.
The stream is defined as:
internal class NonClosingStream : Stream, IDisposable
{
private Stream baseStream;
public NonClosingStream(Stream baseStream)
{
this.baseStream = baseStream;
}
public override bool CanRead{ get { return baseStream.CanRead; } }
public override bool CanSeek{ get { return baseStream.CanSeek; } }
public override bool CanWrite { get { return baseStream.CanWrite; } }
public override void Flush()
{
baseStream.Flush();
}
public override long Length { get { return baseStream.Length; } }
public override long Position
{
get { return baseStream.Position; }
set { baseStream.Position = value; }
}
public override int Read(byte[] buffer, int offset, int count)
{
return baseStream.Read(buffer, offset, count);
}
public override long Seek(long offset, SeekOrigin origin)
{
return baseStream.Seek(offset, origin);
}
public override void SetLength(long value)
{
baseStream.SetLength(value);
}
public override void Write(byte[] buffer, int offset, int count)
{
baseStream.Write(buffer, offset, count);
}
public override void Close()
{
// Disconnects from base stream, but does not close it
this.baseStream = null;
}
void IDisposable.Dispose()
{
// Disconnects from base stream, but does not close it
this.baseStream = null;
}
}
and the read block looks like this:
public T Deserialize<T>(Stream stream)
{
using (NonClosingStream nonClosingStream = new NonClosingStream(stream))
using (BinaryReader reader = new BinaryReader(nonClosingStream, Encoding.ASCII, true))
{
// Read the type name, then convert it to an actual type
String typeName = reader.ReadString();
Type graphType = AvailableTypes.GetType(typeName);
// If a deserializer for this type already exists, use it.
if (deserializerFunctions.ContainsKey(graphType))
{
return (T)deserializerFunctions[graphType](reader);
}
// Otherwise, create one and use it
T graph = (T)FormatterServices.GetUninitializedObject(graphType);
typeof(ServiceSerializer).GetMethod("DeserializeObject",
BindingFlags.NonPublic | BindingFlags.Static)
.MakeGenericMethod(graphType)
.Invoke(this, new Object[] { reader, graph });
return graph;
}
}
what am I doing wrong?
Update
So I wrote this little diddy:
static void Main()
{
MemoryStream stream = new MemoryStream();
using (NonClosingStream nonCloser = new NonClosingStream(stream))
using (BinaryWriter writer = new BinaryWriter(nonCloser))
using (BinaryReader reader= new BinaryReader(nonCloser))
{
writer.Write("Lorem ipsum");
stream.Seek(0, SeekOrigin.Begin);
String data = reader.ReadString();
Console.WriteLine(data);
}
stream.Seek(0, SeekOrigin.Begin);
using (NonClosingStream nonCloser = new NonClosingStream(stream))
using (BinaryWriter writer = new BinaryWriter(nonCloser))
using (BinaryReader reader = new BinaryReader(nonCloser))
{
writer.Write("Lorem ipsum");
stream.Seek(0, SeekOrigin.Begin);
String data = reader.ReadString();
Console.WriteLine(data);
}
Console.ReadLine();
}
and it seems to work fine, the stream stays open like it's supposed to. So I guess the consensus is right. Somehow I'm closing the stream elsewhere. When I figure out what I'll post the results. Thanks all.
Update
Gaaaahhh, I figured out the problem. So the way the code works is that while it serializes/deserializes an object, it then builds a customized serializer out of expression trees and then compiles it so that future serializations are more fluid. That means my code is littered with stuff like this:
Action<BinaryReader, Object> assignmentAction = delegate(BinaryReader bReader, Object oGraph)
{
bReader.ReadByte(); // Read the next action
bReader.ReadString(); // Read the field name
bReader.ReadByte(); // Read the field type
// Call the assignment lambda
assignmentLambda(reader, deserializerFunctions[primitiveType], (T)oGraph);
};
did you catch that? No? Neither did I apparently. Let's add some context:
private static void DeserializeObject<T>(BinaryReader reader, T graph)
{
...
Action<BinaryReader, Object> assignmentAction = delegate(BinaryReader bReader, Object oGraph)
{
bReader.ReadByte(); // Read the next action
bReader.ReadString(); // Read the field name
bReader.ReadByte(); // Read the field type
// Call the assignment lambda
assignmentLambda(reader, deserializerFunctions[primitiveType], (T)oGraph);
};
...
}
The lambda is closing over reader from the outside block, instead of using the bReader provided when the cached deserializer runs. Hence, when the deserializer runs, it's using an already discarded Binary reader object rather than the fresh one being provided to it. I guess the issue wasn't that I was closing the stream, but that I was using a disposed reader. At least that explains why it would work once, and then fail the second time, since the second time it relies on the cached deserializer. Oops!
Thanks all.
Since your stream does not create inner stream most likely outer code closes your inner stream. Chances are your code look like:
NonClosingStream nonClosing;
using(var stream = new FileStream(...))
{
nonClosing = new NonClosingStream(stream );
....
}
// inner stream now closed and nonClosing will fail all operations.
void IDisposable.Dispose()
Your class has two Dispose() methods. The one you explicitly implemented. And the one that you inherited from the Stream class. Problem is, BinaryStream doesn't know beans about yours. It only knows about the one that Stream implements. Furthermore, when you use the BinaryStream(Stream) constructor, the BinaryStream object assumes ownership of the passed Stream object. Which means it will dispose that stream when it gets disposed itself. Perhaps you see the problem now, the inherited Dispose() method will be called, not yours. And it closes the base stream.
This is why Stream implements the Dispose pattern. You'll need to make it look like this instead:
internal class NonClosingStream : Stream {
protected override Dispose(bool disposing) {}
}
It depends on whether the stream which is being wrapped by your NonClosingStream class is referenced elsewhere. If not, then the underlying stream will have no references, so at some point afterwards its finalizer will close the stream.
I'm using the Amazon SDK and I have a method that returns a Stream for an object stored in Amazon S3 service.
It contains something like this:
var request = new GetObjectRequest().WithBucketName(bucketName).WithKey(keyName);
using (var response = client.GetObject(request))
{
return response.ResponseStream;
}
Obviously, when doing this, the stream is not readable from the calling method because the request object has been disposed and when this is done, it closes the stream.
I don't want to download the file to a MemoryStream or a FileStream.
If I don't use the using clause, the garbage collector will dispose the request object at some point so I can't just not use it.
What I'm asking is, is there a way to wrap or copy the Stream into another Stream and then return it without having to download the file?
I'm using .NET 3.5.
Edit: The method is inherited from an abstract class and the caller method doesn't know it is working with Amazon. So it HAS to return a Stream.
You can't work with the stream after it's disposed, but you can postpone disposing the response object until after the response stream has been used. There are three options I can suggest.
Return Response. One option is to return the response object to the caller. The caller can access the contained response stream and then dispose the response when done. This is the easiest change but requires the caller to change as well.
Wrap the stream. Instead of returning the response stream directly, create a new object that extends Stream and wraps the response stream but also has a reference to the response itself. Then when your wrapper is disposed, you can internally dispose the response object. This requires only changing your called code as long as the type being returned is just Stream.
Callback. Don't return anything from the method and use a callback mechanism instead. Accept an Action<Stream> as a parameter and call this callback with the stream. That way the callers code is called and you still have control over disposing the response and stream. This is the safest mechanism since you're not relying on the caller to dispose anything, but requires the most changes.
There is a method OpenStream in TransferUtility class which returns a stream object.
public Stream OpenStream(
String bucketName,
String key
)
I looked through the source code of AWSSDK, and found in the SDK the OpenStream just returns the response stream directly. (It doesn't use "using" statement on response object.)
If your function returns the response object (without using the using statement), and the caller assigns it to a variable, there will still be a reference to the response object. Thus it won't be eligible garbage collected.
Had the same issue (I thought). But have you tried to not use "using". This will not use the stream and send it to the caller who will have the responsibility to dispose it. As simple as that.
var request = new GetObjectRequest { BucketName = containerName, Key = blobName };
GetObjectResponse response = null;
try
{
response = client.GetObject(request));
}
catch (AmazonS3Exception ex)
{
if ((ex.ErrorCode == "NoSuchBucket") || (ex.ErrorCode == "AccessDenied") || (ex.ErrorCode == "InvalidBucketName") || (ex.ErrorCode == "NoSuchKey"))
{
return null;
}
throw;
}
return response.ResponseStream;
For completeness, and since I went with #Samuel option number 2 (Wrap the stream) which #spakinz commented he did too, I include here my implementation of what I called AmazonS3Stream
public class AmazonS3Stream : Stream
{
private Stream stream;
private GetObjectResponse response;
public AmazonS3Stream(GetObjectResponse response)
{
this.stream = response.ResponseStream;
this.response = response;
}
// The whole purpose of this class
protected override void Dispose(bool disposing)
{
// base.Dispose(disposing); // Do we really need this line? Probably not since I tested it and I can see that the stream is disposed when Response.Dispose is called by itself. And that makes sense because we know that this.stream is pointing to response.ResponseStream (that's what we declared in the constructor: this.stream = response.ResponseStream; ) So, what do we expect from response.Dispose() ? Obviously the first thing it would do is call ResponseStream.Dispose()
response.Dispose();
}
public override long Position
{
get { return stream.Position; }
set { stream.Position = Position; }
}
public override long Length
{
get { return stream.Length; }
}
public override bool CanRead
{
get { return stream.CanRead; }
}
public override bool CanSeek
{
get { return stream.CanSeek; }
}
public override bool CanWrite
{
get { return stream.CanWrite; }
}
public override void Flush()
{
stream.Flush();
}
public override void Write(byte[] buffer, int offset, int count)
{
stream.Write(buffer, offset, count);
}
public override void SetLength(long value)
{
stream.SetLength(value);
}
public override long Seek(long offset, SeekOrigin origin)
{
return stream.Seek(offset, origin);
}
public override int Read(byte[] buffer, int offset, int count)
{
return stream.Read(buffer, offset, count);
}
}
To add a code example to #Jun Y.'s answer. This is what I did and it was the cleanest solution by far.
using (var client = new AmazonS3Client(Amazon.RegionEndpoint.USEast2))
{
var transferUtility = new TransferUtility(client);
return await transferUtility.OpenStreamAsync(S3BucketName, key);
}