@@ -45,7 +45,7 @@ public async Task<Result<BlobMetadata>> UploadFile(Stream stream, string apiUrl,
4545 using var formData = new MultipartFormDataContent ( ) ;
4646 formData . Add ( streamContent , contentName , contentName ) ;
4747
48- var response = await httpClient . PostAsync ( apiUrl , formData , cancellationToken ) ;
48+ using var response = await httpClient . PostAsync ( apiUrl , formData , cancellationToken ) ;
4949
5050 if ( response . IsSuccessStatusCode )
5151 return await response . Content . ReadFromJsonAsync < Result < BlobMetadata > > ( cancellationToken : cancellationToken ) ;
@@ -63,7 +63,7 @@ public async Task<Result<BlobMetadata>> UploadFile(FileInfo fileInfo, string api
6363 {
6464 formData . Add ( streamContent , contentName , contentName ) ;
6565
66- var response = await httpClient . PostAsync ( apiUrl , formData , cancellationToken ) ;
66+ using var response = await httpClient . PostAsync ( apiUrl , formData , cancellationToken ) ;
6767
6868 if ( response . IsSuccessStatusCode )
6969 {
@@ -77,27 +77,21 @@ public async Task<Result<BlobMetadata>> UploadFile(FileInfo fileInfo, string api
7777
7878 public async Task < Result < BlobMetadata > > UploadFile ( byte [ ] bytes , string apiUrl , string contentName , CancellationToken cancellationToken = default )
7979 {
80- using ( var stream = new MemoryStream ( ) )
81- {
82- stream . Write ( bytes , 0 , bytes . Length ) ;
83-
84- using var streamContent = new StreamContent ( stream ) ;
85-
86- using ( var formData = new MultipartFormDataContent ( ) )
87- {
88- formData . Add ( streamContent , contentName , contentName ) ;
80+ using var stream = new MemoryStream ( bytes , writable : false ) ;
81+ using var streamContent = new StreamContent ( stream ) ;
82+ using var formData = new MultipartFormDataContent ( ) ;
8983
90- var response = await httpClient . PostAsync ( apiUrl , formData , cancellationToken ) ;
84+ formData . Add ( streamContent , contentName , contentName ) ;
9185
92- if ( response . IsSuccessStatusCode )
93- {
94- var result = await response . Content . ReadFromJsonAsync < Result < BlobMetadata > > ( cancellationToken : cancellationToken ) ;
95- return result ;
96- }
86+ using var response = await httpClient . PostAsync ( apiUrl , formData , cancellationToken ) ;
9787
98- return Result < BlobMetadata > . Fail ( response . StatusCode ) ;
99- }
88+ if ( response . IsSuccessStatusCode )
89+ {
90+ var result = await response . Content . ReadFromJsonAsync < Result < BlobMetadata > > ( cancellationToken : cancellationToken ) ;
91+ return result ;
10092 }
93+
94+ return Result < BlobMetadata > . Fail ( response . StatusCode ) ;
10195 }
10296
10397 public async Task < Result < BlobMetadata > > UploadFile ( string base64 , string apiUrl , string contentName ,
@@ -110,7 +104,7 @@ public async Task<Result<BlobMetadata>> UploadFile(string base64, string apiUrl,
110104
111105 formData . Add ( fileContent , contentName , contentName ) ;
112106
113- var response = await httpClient . PostAsync ( apiUrl , formData , cancellationToken ) ;
107+ using var response = await httpClient . PostAsync ( apiUrl , formData , cancellationToken ) ;
114108
115109 if ( response . IsSuccessStatusCode )
116110 return await response . Content . ReadFromJsonAsync < Result < BlobMetadata > > ( cancellationToken : cancellationToken ) ;
@@ -188,11 +182,13 @@ public async Task<Result<uint>> UploadLargeFile(Stream file, string uploadApiUrl
188182 formData . Add ( new StringContent ( bytesRead . ToString ( ) ) , "Payload.ChunkSize" ) ;
189183 formData . Add ( new StringContent ( totalChunks . ToString ( ) ) , "Payload.TotalChunks" ) ;
190184
191- var response = await httpClient . PostAsync ( uploadApiUrl , formData , cancellationToken ) ;
192- if ( ! response . IsSuccessStatusCode )
185+ using ( var response = await httpClient . PostAsync ( uploadApiUrl , formData , cancellationToken ) )
193186 {
194- var message = await response . Content . ReadAsStringAsync ( cancellationToken ) ;
195- return Result < uint > . Fail ( response . StatusCode , message ) ;
187+ if ( ! response . IsSuccessStatusCode )
188+ {
189+ var message = await response . Content . ReadAsStringAsync ( cancellationToken ) ;
190+ return Result < uint > . Fail ( response . StatusCode , message ) ;
191+ }
196192 }
197193
198194 transmitted += bytesRead ;
@@ -230,7 +226,7 @@ public async Task<Result<uint>> UploadLargeFile(Stream file, string uploadApiUrl
230226 KeepMergedFile = false
231227 } ;
232228
233- var mergeResult = await httpClient . PostAsJsonAsync ( completeApiUrl , completePayload , cancellationToken ) ;
229+ using var mergeResult = await httpClient . PostAsJsonAsync ( completeApiUrl , completePayload , cancellationToken ) ;
234230 if ( ! mergeResult . IsSuccessStatusCode )
235231 {
236232 var message = await mergeResult . Content . ReadAsStringAsync ( cancellationToken ) ;
@@ -308,14 +304,25 @@ public async Task<Result<Stream>> GetFileStream(string fileName, string apiUrl,
308304 {
309305 try
310306 {
311- var response = await httpClient . GetAsync ( $ "{ apiUrl } /{ fileName } ") ;
312- if ( response . IsSuccessStatusCode )
307+ var response = await httpClient . GetAsync ( $ "{ apiUrl } /{ fileName } ", HttpCompletionOption . ResponseHeadersRead , cancellationToken ) ;
308+ if ( ! response . IsSuccessStatusCode )
309+ {
310+ response . Dispose ( ) ;
311+ return Result < Stream > . Fail ( response . StatusCode ) ;
312+ }
313+
314+ Stream contentStream ;
315+ try
316+ {
317+ contentStream = await response . Content . ReadAsStreamAsync ( cancellationToken ) ;
318+ }
319+ catch
313320 {
314- var stream = await response . Content . ReadAsStreamAsync ( ) ;
315- return Result < Stream > . Succeed ( stream ) ;
321+ response . Dispose ( ) ;
322+ throw ;
316323 }
317324
318- return Result < Stream > . Fail ( response . StatusCode ) ;
325+ return Result < Stream > . Succeed ( new HttpResponseMessageStream ( contentStream , response ) ) ;
319326 }
320327 catch ( HttpRequestException e ) when ( e . StatusCode != null )
321328 {
@@ -328,6 +335,82 @@ public async Task<Result<Stream>> GetFileStream(string fileName, string apiUrl,
328335 }
329336}
330337
338+ file sealed class HttpResponseMessageStream ( Stream innerStream , HttpResponseMessage response ) : Stream
339+ {
340+ private readonly Stream _innerStream = innerStream ?? throw new ArgumentNullException ( nameof ( innerStream ) ) ;
341+ private readonly HttpResponseMessage _response = response ?? throw new ArgumentNullException ( nameof ( response ) ) ;
342+
343+ public override bool CanRead => _innerStream . CanRead ;
344+ public override bool CanSeek => _innerStream . CanSeek ;
345+ public override bool CanWrite => _innerStream . CanWrite ;
346+ public override long Length => _innerStream . Length ;
347+
348+ public override long Position
349+ {
350+ get => _innerStream . Position ;
351+ set => _innerStream . Position = value ;
352+ }
353+
354+ public override void Flush ( ) => _innerStream . Flush ( ) ;
355+
356+ public override Task FlushAsync ( CancellationToken cancellationToken ) => _innerStream . FlushAsync ( cancellationToken ) ;
357+
358+ public override int Read ( byte [ ] buffer , int offset , int count ) => _innerStream . Read ( buffer , offset , count ) ;
359+
360+ public override int Read ( Span < byte > buffer ) => _innerStream . Read ( buffer ) ;
361+
362+ public override Task < int > ReadAsync ( byte [ ] buffer , int offset , int count , CancellationToken cancellationToken ) =>
363+ _innerStream . ReadAsync ( buffer , offset , count , cancellationToken ) ;
364+
365+ public override ValueTask < int > ReadAsync ( Memory < byte > buffer , CancellationToken cancellationToken = default ) =>
366+ _innerStream . ReadAsync ( buffer , cancellationToken ) ;
367+
368+ public override long Seek ( long offset , SeekOrigin origin ) => _innerStream . Seek ( offset , origin ) ;
369+
370+ public override void SetLength ( long value ) => _innerStream . SetLength ( value ) ;
371+
372+ public override void Write ( byte [ ] buffer , int offset , int count ) => _innerStream . Write ( buffer , offset , count ) ;
373+
374+ public override void Write ( ReadOnlySpan < byte > buffer ) => _innerStream . Write ( buffer ) ;
375+
376+ public override Task WriteAsync ( byte [ ] buffer , int offset , int count , CancellationToken cancellationToken ) =>
377+ _innerStream . WriteAsync ( buffer , offset , count , cancellationToken ) ;
378+
379+ public override ValueTask WriteAsync ( ReadOnlyMemory < byte > buffer , CancellationToken cancellationToken = default ) =>
380+ _innerStream . WriteAsync ( buffer , cancellationToken ) ;
381+
382+ protected override void Dispose ( bool disposing )
383+ {
384+ if ( disposing )
385+ {
386+ try
387+ {
388+ _innerStream . Dispose ( ) ;
389+ }
390+ finally
391+ {
392+ _response . Dispose ( ) ;
393+ }
394+ }
395+
396+ base . Dispose ( disposing ) ;
397+ }
398+
399+ public override async ValueTask DisposeAsync ( )
400+ {
401+ try
402+ {
403+ await _innerStream . DisposeAsync ( ) ;
404+ }
405+ finally
406+ {
407+ _response . Dispose ( ) ;
408+ }
409+
410+ await base . DisposeAsync ( ) ;
411+ }
412+ }
413+
331414file class ChunkUploadCompleteRequestDto
332415{
333416 public string UploadId { get ; set ; } = string . Empty ;
0 commit comments