I have a method that take Stream parameter and pass it to server
public async Task<string> Execute(Stream archive)
{
archive.Seek(0, SeekOrigin.Begin);
using var content = new MultipartFormDataContent();
content.Add(new StreamContent(archive), "file1", "file1");
var result = "";
using (var response = await _client.PostAsync(_uri, content))
{
if (response.IsSuccessStatusCode)
{
var stringResult = await response.Content.ReadAsStringAsync();
result = stringResult;
}
}
// here archive is already disposed
return result;
}
Now I implement the retry policy of this method. If outside code calling this method gets "" as result, then it tries to call this method againg. But the archive is disposed to that moment. I see that archive stream is disposed immediately after disposing of response. Why? What should I do if I need stream parameter outside after this method?
It's the StreamContent that will dispose the Stream, as states in it's source. And that will be disposed by the MultipartContent. And that will be disposed in PostAsync... all though the chain.
A solution is to subclass the Stream and remove the dispose method, like proposed here. but you'll have to make sure the original stream gets disposed yourself!.
Edit: update. Stream is an abstract class, so it would be easier if you know the specific stream type, e.g.
public sealed class NoDisposeMemoryStream : MemoryStream
{
protected override void Dispose(bool disposing) { }
}
Else you will need to write your own complete Stream wrapper, see bottom.
Another solution is to implement the retry mechanism in the innermost using block, resetting the archive seek origin every fail. That's likely safer.
public sealed class NoDisposeStream : Stream
{
private Stream _original;
public NoDisposeStream(Stream original) => _original = original
?? throw new ArgumentNullException(nameof(original));
public override bool CanRead => _original.CanRead;
public override bool CanSeek => _original.CanSeek;
public override bool CanWrite => _original.CanWrite;
public override long Length => _original.Length;
public override long Position { get => _original.Position; set { _original.Position = value; } }
public override void Flush() => _original.Flush();
public override int Read(byte[] buffer, int offset, int count) => _original.Read(buffer, offset, count);
public override long Seek(long offset, SeekOrigin origin) => _original.Seek(offset, origin);
public override void SetLength(long value) => _original.SetLength(value);
public override void Write(byte[] buffer, int offset, int count) => _original.Write(buffer, offset, count);
protected override void Dispose(bool disposing) { }
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With