System.ObjectDisposedException
An ObjectDisposedException is thrown when you call a member on an object that has already been disposed. Streams, readers, database connections, HttpClient and DbContext all clean up resources in Dispose and refuse to be used after that.
The message names the type, for example Cannot access a disposed object. Object name: 'System.Net.Http.HttpClient'. The bug is not in the object, but in the code that disposed it too early, or kept using it for too long.
Minimum version: >= 1.1 >= Core 1.0
Statistics
Common causes
Something called Dispose, directly or through using, before you were done. These are the common ways that happens.
Using an object after its using block
A using statement disposes the object at the end of the block. A reference that escapes the block, such as one that is stored in a field or returned, points to a disposed object.
var writer = new StreamWriter(new MemoryStream());
writer.Dispose();
writer.WriteLine("done"); // ObjectDisposedException
Keep the object open until the work is done, and dispose it last:
using var writer = new StreamWriter(new MemoryStream());
writer.WriteLine("done");
Returning something that depends on a disposed object
A reader that wraps a stream does not own the stream in a way you can see. If the method disposes the stream when it returns, the reader fails the first time it is used.
public StreamReader Open(string path)
{
using var stream = File.OpenRead(path);
return new StreamReader(stream); // the stream is disposed when the method returns
}
Return the reader without disposing the stream, and let the caller dispose the reader. It disposes the stream too:
public StreamReader Open(string path)
{
return new StreamReader(File.OpenRead(path));
}
A scoped service that outlives its scope
In ASP.NET Core, a DbContext or another scoped service is disposed when the request ends. Background work that was started in the request, such as a Task.Run or a fire-and-forget call, can run after that and fail with this exception.
Create a new scope for the background work, and get the services from it:
public async Task RunAsync(IServiceScopeFactory scopeFactory)
{
using var scope = scopeFactory.CreateScope();
var orders = scope.ServiceProvider.GetRequiredService<IOrderService>();
await Task.CompletedTask;
}
How to fix it and prevent it
Let the owner dispose it
Decide which code owns an object, and dispose it there only. Objects that you get from dependency injection are disposed by the container, so do not wrap them in using yourself.
Await before the using block ends
A using around an async call that you did not await disposes the object while the call is still running. Use await using and await every call.
await using var stream = new MemoryStream();
await stream.WriteAsync(new byte[] { 1, 2, 3 });
Reuse HttpClient through the factory
Do not create and dispose an HttpClient for each request, and do not dispose one that you share. Use IHttpClientFactory, which handles the lifetime.
How to read the stack trace
The message names the object that was disposed, and the frame below shows who used it:
System.ObjectDisposedException: Cannot write to a closed TextWriter.
Object name: 'StreamWriter'.
at System.IO.StreamWriter.<ThrowIfDisposed>g__ThrowObjectDisposedException|80_0()
at System.IO.StreamWriter.WriteLine(String value)
at Shop.Services.ReportWriter.Write(String line) in C:\src\Shop\Services\ReportWriter.cs:line 18
at Program.<Main>$(String[] args) in C:\src\Shop\Program.cs:line 6
The disposed object is a StreamWriter, and the failing call is on line 18 of ReportWriter.cs. The question is who disposed it before that line. Search for Dispose and using on that field, and for a second owner that disposes it.
Should you catch it?
No. It points to a bug in the lifetime of an object, so fix the order of the calls instead of catching it.
The one place it is fine is when you stop work that is running in the background while the application shuts down. Catch it there, and let the shutdown go on.
Find ObjectDisposedException before your users do
elmah.io logs every unhandled exception in your .NET application with its stack trace and request details, groups identical errors and notifies you when a new one appears.
Start free trialRelated exceptions
- InvalidOperationException is the base class, thrown when a call is not valid for the state of the object.
- NullReferenceException is thrown when a reference is null, which is another way to use an object that is gone.
- IOException is thrown for other problems with streams and files.
Frequently asked questions
How do I find who disposed the object?
Search for Dispose and using on the object. In a debugger, set a breakpoint in the Dispose method of your own types, and look at the call stack.
Why does my DbContext get disposed?
It is scoped to the request, and the container disposes it when the request ends. Use a new scope, or IDbContextFactory, for work that runs longer than the request.
Is it safe to call Dispose twice?
It should be. Most types allow it, but any other member throws after the first call.
Should I wrap everything in using?
Wrap what you create and own. Do not dispose what was passed in to you, or what comes from the container.
Let your AI agent track it down
Connect Claude Code, Cursor, VS Code or Visual Studio to the elmah.io MCP server and ask your agent to look into ObjectDisposedException for you. For example:
The agent reads the stack trace and request details from elmah.io, finds the code in your repository and proposes a fix. In Claude Code, add the server with one command:
claude mcp add --transport http --client-id claudecode elmahio https://mcp.elmah.io/mcp
The MCP server is included on every plan and is currently in beta. Set up the MCP server.
Further reading
YouTube videos
Answers from Stack Overflow
You should suppress the warnings in this case. Code that deals with disposables should be consistent, and you shouldn't have to care that other classes take ownership of the disposables you created and also call Dispose on them.
[SuppressMessage("Microsoft.Usage", "CA2202:Do not dispose objects multiple times")]
public static byte[] Encrypt(string data, byte[] key, byte[] iv) {
using (var memoryStream = new MemoryStream()) {
using (var cryptograph = new DESCryptoServiceProvider())
using (var cryptoStream = new CryptoStream(memoryStream, cryptograph.CreateEncryptor(key, iv), CryptoStreamMode.Write))
using (var streamWriter = new StreamWriter(cryptoStream)) {
streamWriter.Write(data);
}
return memoryStream.ToArray();
}
}
UPDATE: In the IDisposable.Dispose documentation you can read this:
If an object's Dispose method is called more than once, the object must ignore all calls after the first one. The object must not throw an exception if its Dispose method is called multiple times.
It can be argued that this rule exists so that developers can employ the using statement sanely in a cascade of disposables, like I've shown above (or maybe this is just a nice side-effect). By the same token, then, CA2202 serves no useful purpose, and it should be suppressed project-wise. The real culprit would be a faulty implementation of Dispose, and CA1065 should take care of that (if it's under your responsibility).
By Jordão. Read the original answer on Stack Overflow.
Just a guess in what causes your error:
You are using DI and async calls. If, somewhere in your call stack, you return a void instead of Task, you get the described behavior. At that point, the call is ended and the context disposed. So check if you have an async call that returns a void instead of Task. If you change the return value, the ObjectDisposedException is probably fixed.
public static class DataSeedExtensions {
private static IServiceProvider _provider;
public static async Task SeedData(this IApplicationBuilder builder) { //This line of code
_provider = builder.ApplicationServices;
_type = type;
using (Context context = (Context)_provider.GetService<Context>()) {
await context.Database.MigrateAsync();
// Insert data code
}
}
And in configure:
if (hostingEnvironment.IsDevelopment()){
await applicationBuilder.SeedData();
}
Blog post on how to fix this error: Cannot access a disposed object in ASP.NET Core when injecting DbContext
By Peter. Read the original answer on Stack Overflow.
Instead of implementing retry functionality that wraps the HttpClient, consider constructing the HttpClient with a HttpMessageHandler that performs the retry logic internally. For example:
public class RetryHandler : DelegatingHandler
{
// Strongly consider limiting the number of retries - "retry forever" is
// probably not the most user friendly way you could respond to "the
// network cable got pulled out."
private const int MaxRetries = 3;
public RetryHandler(HttpMessageHandler innerHandler)
: base(innerHandler)
{ }
protected override async Task<HttpResponseMessage> SendAsync(
HttpRequestMessage request,
CancellationToken cancellationToken)
{
HttpResponseMessage response = null;
for (int i = 0; i < MaxRetries; i++)
{
response = await base.SendAsync(request, cancellationToken);
if (response.IsSuccessStatusCode) {
return response;
}
}
return response;
}
}
public class BusinessLogic
{
public void FetchSomeThingsSynchronously()
{
// ...
// Consider abstracting this construction to a factory or IoC container
using (var client = new HttpClient(new RetryHandler(new HttpClientHandler())))
{
myResult = client.PostAsync(yourUri, yourHttpContent).Result;
}
// ...
}
}
By Dan Bjorge. Read the original answer on Stack Overflow.
ASP.NET Core 2.1 Answer
ASP.NET Core 2.1 added support for Polly directly. Here UnreliableEndpointCallerService is a class which accepts a HttpClient in its constructor. Failed requests will retry with an exponential back-off so that the next retry takes place in an exponentially longer time after the previous one:
services
.AddHttpClient<UnreliableEndpointCallerService>()
.AddTransientHttpErrorPolicy(
x => x.WaitAndRetryAsync(3, retryAttempt => TimeSpan.FromSeconds(Math.Pow(3, retryAttempt))));
Also, consider reading my blog post "Optimally Configuring HttpClientFactory".
Other Platforms Answer
This implementation uses Polly to retry with an exponential back-off so that the next retry takes place in an exponentially longer time after the previous one. It also retries if a HttpRequestException or TaskCanceledException is thrown due to a timeout. Polly is much easier to use than Topaz.
public class HttpRetryMessageHandler : DelegatingHandler
{
public HttpRetryMessageHandler(HttpClientHandler handler) : base(handler) {}
protected override Task<HttpResponseMessage> SendAsync(
HttpRequestMessage request,
CancellationToken cancellationToken) =>
Policy
.Handle<HttpRequestException>()
.Or<TaskCanceledException>()
.OrResult<HttpResponseMessage>(x => !x.IsSuccessStatusCode)
.WaitAndRetryAsync(3, retryAttempt => TimeSpan.FromSeconds(Math.Pow(3, retryAttempt)))
.ExecuteAsync(() => base.SendAsync(request, cancellationToken));
}
using (var client = new HttpClient(new HttpRetryMessageHandler(new HttpClientHandler())))
{
var result = await client.GetAsync("http://example.com");
}
By Muhammad Rehan Saeed. Read the original answer on Stack Overflow.
Update for ASP.NET Core 2.1
In ASP.NET Core 2.1 the methods changed slightly. The general method is similar to the 2.0, just the methods name and return types have been changed.
public static void Main(string[] args)
{
CreateWebHostBuilder(args)
.Build()
.Seed();
}
public static IWebHostBuilder CreateWebHostBuilder(string[] args)
{
return new WebHostBuilder()
...; // Do not call .Build() here
}
Applies for ASP.NET Core 2.0
With ASP.NET Core 2.0 there have been some changes in how EF Core tools (dotnet ef migrations etc.) determine the DbContext and connection string at design time.
The below answer leads that the migrations and seeding are applied when calling any of the dotnet ef xxx commands.
The new pattern for getting a design time instance for the EF Core tools is by using an BuildHostWeb static method.
As per this announcement, EF Core will now use the static BuildWebHost method which configures the whole application, but doesn't run it.
public class Program { public static void Main(string[] args) { var host = BuildWebHost(args); host.Run(); } // Tools will use this to get application services public static IWebHost BuildWebHost(string[] args) => new WebHostBuilder() .UseKestrel() .UseContentRoot(Directory.GetCurrentDirectory()) .UseIISIntegration() .UseStartup<Startup>() .Build(); }
Replace this in your old Main method
public static void Main(string[] args)
{
var host = BuildWebHost(args)
.Seed();
host.Run();
}
Where Seed is an extension method:
public static IWebHost Seed(this IWebHost webhost)
{
using (var scope = webhost.Services.GetService<IServiceScopeFactory>().CreateScope())
{
// alternatively resolve UserManager instead and pass that if only think you want to seed are the users
using (var dbContext = scope.ServiceProvider.GetRequiredService<ApplicationDbContext>())
{
SeedData.SeedAsync(dbContext).GetAwaiter().GetResult();
}
}
}
public static class SeedData
{
public static async Task SeedAsync(ApplicationDbContext dbContext)
{
dbContext.Users.Add(new User { Id = 1, Username = "admin", PasswordHash = ... });
}
}
Old Answer, still applies to ASP.NET Core 1.x
There is a semi-official pattern on how to seed Entity Framework Core in ASP.NET Core application you should apply, because during application startup there is no Request and hence no RequestServices (which resolves scoped services).
In essence it boils down to creating a new scope, resolve the types you need and dispose the scope again once you're finished.
// serviceProvider is app.ApplicationServices from Configure(IApplicationBuilder app) method
using (var serviceScope = serviceProvider.GetRequiredService<IServiceScopeFactory>().CreateScope())
{
var db = serviceScope.ServiceProvider.GetService<AppDbContext>();
if (await db.Database.EnsureCreatedAsync())
{
await SeedDatabase(db);
}
}
One of the reasons directly resolving a service via app.ApplicationServices.GetService<MyService>() is that ApplicationServices is the application (or lifetime) scope provider and the services resolved here stay alive until the application is shut down.
Usually the scoped container will resolve from it's parent container, if the object already exists there. So if you instantiate the DbContext this way in the application, it will be available in ApplicationServices container and when a request happens, a child container will be created.
Now when resolving the DbContext it won't be resolved as scoped, because it already exists in the parent container, so the instance of the parent container will be returned instead. But since it has been disposed during the seeding, it won't be accessible.
A scope container is nothing else then a singleton container with limited lifetime.
So never resolve scoped services in Application startup w/o using the pattern above of first creating a scope and resolving from it.
By Tseng. Read the original answer on Stack Overflow.
Source: Stack Overflow