System.Net.Http.HttpRequestException: Error while copying content to a stream. ---> System.ObjectDisposedException: Cannot access a disposed object

Shashank Gaddam [C] 20 Reputation points
2025-03-27T07:29:46.95+00:00

System.Net.Http.HttpRequestException: Error while copying content to a stream. ---> System.ObjectDisposedException: Cannot access a disposed object

I am getting above error for the first API call at 'await httpResponseMessage.Content.ReadAsStringAsync();', and consecutive API calls are working fine,

I am using Polly and Refit

<PackageReference Include="Polly" Version="8.5.0" />
<PackageReference Include="Refit" Version="8.0.0" />
<PackageReference Include="Refit.HttpClientFactory" Version="8.0.0" />
<PackageReference Include="Refit.Newtonsoft.Json" Version="8.0.0" />


Below is the sample code

private async Task GetMasterOptions()
{
    try
    {
        var httpResponseMessage = await TestService.GetMasterDataOptions("testCategory");

        if (httpResponseMessage != null && httpResponseMessage.IsSuccessStatusCode && httpResponseMessage.StatusCode == System.Net.HttpStatusCode.OK)
        {
            var content = await httpResponseMessage.Content.ReadAsStringAsync();

            var response = JsonConvert.DeserializeObject<List<MasterDataOptionsAPIModel>>(content);
        }
    }
    catch(Exception ex)
    {
        
    }

}

public class TestService(ITestAPIService _testAPIService) : BaseAPIService, ITestService
{
    public async Task<HttpResponseMessage> GetMasterDataOptions(string optionCategory)
    {
        var cts = new CancellationTokenSource();

        Task<HttpResponseMessage> task = AttemptAndRetry(() => _testAPIService.GetMasterDataOptions(optionCategory), cts.Token);

        runningTasks.Add(task.Id, cts);

        return await task;
    }
}

 private static Task<T> AttemptAndRetry<T>(Func<Task<T>> action, CancellationToken cancellationToken, int numRetries = 3)
 {
     return Policy.Handle<Exception>(shouldHandleException)
                  .WaitAndRetryAsync(numRetries, retryAttempt)
                  .ExecuteAsync(token => action(), cancellationToken);

     static TimeSpan retryAttempt(int attemptNumber) => TimeSpan.FromSeconds(Math.Pow(2, attemptNumber));

     static bool shouldHandleException(Exception exception)
     {
         if (exception is ApiException apiException)
             return !isForbiddenOrUnauthorized(apiException);

         return true;

         static bool isForbiddenOrUnauthorized(ApiException apiException)
         {
             return apiException.StatusCode is System.Net.HttpStatusCode.Forbidden
            || apiException.StatusCode is System.Net.HttpStatusCode.Unauthorized;
         }
     }
 }

 [Headers("User-Agent: " + nameof(Test), "Accept-Encoding: gzip", "Accept: application/json")]
 public interface ITestAPIService
 {
	 [Get("/API/MasterData/Options")]
	 Task<HttpResponseMessage> GetMasterDataOptions([AliasAs("optionCategory")] string optionCategory);

 }

 builder.Services.AddRefitClient<ITestAPIService>()
     .ConfigureHttpClient(c => { 
         c.BaseAddress = new Uri(AppConstants.BaseURL);
         c.Timeout = TimeSpan.FromSeconds(20);
         c.DefaultRequestHeaders.Add(AppConstants.SubscriptionKey, AppConstants.SubscriptionKeyValue);
     })
     .ConfigurePrimaryHttpMessageHandler(() =>
     {
         var innerHandler = new HttpClientHandler
         {
             AutomaticDecompression = System.Net.DecompressionMethods.GZip | System.Net.DecompressionMethods.Deflate
         };

         return new NonDisposableHttpClientHandler(innerHandler);
     });

.NET MAUI
.NET MAUI
A Microsoft open-source framework for building native device applications spanning mobile, tablet, and desktop.
4,075 questions
{count} votes

Accepted answer
  1. Santiago Porras Rodríguez 75 Reputation points MVP
    2025-03-27T18:27:16.6266667+00:00

    The error System.Net.Http.HttpRequestException: Error while copying content to a stream. ---> System.ObjectDisposedException: Cannot access a disposed object typically occurs when attempting to access an object (like the content stream of an HTTP response) that has already been disposed of or released.

    Here are the potential issues and solutions based on your code:

    1. Improper usage of HttpClient or its handler
    • Although you're using a custom NonDisposableHttpClientHandler, it's possible that the client or its associated resources (like the stream) are being disposed of before operations are complete.
    1. Cancellation Token Handling
    • In the AttemptAndRetry method, you're passing a CancellationToken. If the token gets triggered or its context is disposed prematurely, it could lead to the issue.
    var cts = new CancellationTokenSource();
    Task<HttpResponseMessage> task = AttemptAndRetry(() => _testAPIService.GetMasterDataOptions(optionCategory), cts.Token);
    

    If the cancellation token is unnecessary, consider using CancellationToken.None.

    1. Ensure Proper Stream Handling
    • The content of an HTTP response stream can only be read once. If you need to process it multiple times, save it in a variable:
    var content = await httpResponseMessage.Content.ReadAsStringAsync();
    

    Avoid accessing httpResponseMessage.Content after reading it.

    1. Potential Context Switching
    • Use .ConfigureAwait(false) to avoid issues with multithreading or context switching:
    var content = await httpResponseMessage.Content.ReadAsStringAsync().ConfigureAwait(false);
    
    1. Check NonDisposableHttpClientHandler
    • Double-check the implementation of NonDisposableHttpClientHandler to ensure it's not prematurely disposing of resources.
    1. Handle Exceptions in Detail
    • Always provide detailed exception logging for better debugging:
    catch (Exception ex)
    {
        Console.WriteLine($"Error: {ex.Message}");
    }
    
    0 comments No comments

0 additional answers

Sort by: Most helpful

Your answer

Answers can be marked as Accepted Answers by the question author, which helps users to know the answer solved the author's problem.