How to use the same stream twice #1696
-
Hi there, I try to send the same stream twice via refit. But when the first request is done, Refit just disposes my stream. My Refit Interface using Refit;
namespace CK.Kalypso.BinaryStore.VirusScanner.Services;
public interface IExampleApi
{
[Multipart]
[Post("/api/scanFile")]
Task<MyResult> RequestAsync([AliasAs("file")] MultipartItem stream, CancellationToken cancellationToken);
}
public record MyResult(string text); My Api Call Code using Refit;
namespace CK.Kalypso.BinaryStore.VirusScanner.Services;
public class ExampleApi
{
private readonly IExampleApi _exampleApi;
public ExampleApi(IExampleApi exampleApi)
{
_exampleApi = exampleApi;
}
public async Task<MyResult> RequestAsync(Stream stream, string fileName, CancellationToken cancellationToken)
{
if (!stream.CanSeek)
throw new ArgumentException($"{nameof(stream)} must be seekable!");
stream.Seek(0, SeekOrigin.Begin);
var result = await _exampleApi.RequestAsync(new StreamPart(stream, fileName), cancellationToken);
if (!stream.CanSeek)
throw new ArgumentException($"{nameof(stream)} must be seekable!");
stream.Seek(0, SeekOrigin.Begin); // Here it fails with an Object Disposed Exception
var result2 = await _exampleApi.RequestAsync(new StreamPart(stream, fileName), cancellationToken);
return result ?? result2;
}
} When the stream was sent once it get disposed and I don't know why, because it forces me to copy it an load all the contents into memory (files up to 200mb are possible). Thanks for any help! |
Beta Was this translation helpful? Give feedback.
Replies: 1 comment
-
I fixed this problem for myself. This is what i came up with: public class KeepStreamAliveStreamDecorator : Stream
{
private readonly Stream _original;
public KeepStreamAliveStreamDecorator(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);
} using Refit;
namespace CK.Kalypso.BinaryStore.VirusScanner.Services;
public class ExampleApi
{
private readonly IExampleApi _exampleApi;
public ExampleApi(IExampleApi exampleApi)
{
_exampleApi = exampleApi;
}
public async Task<MyResult> RequestAsync(Stream stream, string fileName, CancellationToken cancellationToken)
{
if (!stream.CanSeek)
throw new ArgumentException($"{nameof(stream)} must be seekable!");
stream.Seek(0, SeekOrigin.Begin);
await using var streamDecorator = new KeepStreamAliveStreamDecorator(stream);
var result = await _exampleApi.RequestAsync(new StreamPart(streamDecorator, fileName), cancellationToken);
if (!stream.CanSeek)
throw new ArgumentException($"{nameof(stream)} must be seekable!");
stream.Seek(0, SeekOrigin.Begin); // Here it fails with an Object Disposed Exception
var result2 = await _exampleApi.RequestAsync(new StreamPart(stream, fileName), cancellationToken);
return result ?? result2;
}
} I wrap the stream before the first request in a decorator which prevents it from being disposed. So the underlying framework can throw away the decorator instance without touching the Dispose/Close/Whatever of my passed stream. Sincerely snailcatcher |
Beta Was this translation helpful? Give feedback.
I fixed this problem for myself. This is what i came up with: