Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Disposing of HttpResponseMessage is calling disposing of request's stream

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?

like image 259
vitm Avatar asked Oct 29 '25 20:10

vitm


1 Answers

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) { }
    }
like image 142
JHBonarius Avatar answered Oct 31 '25 10:10

JHBonarius



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!