♻️ What Is the Disposable Pattern?
The Disposable Pattern in .NET Core is a design pattern used to release unmanaged resources like file handles, database connections or memory buffers. It relies on the IDisposable interface to define a standard way to free resources deterministically.
This pattern is essential when your object holds non-memory resources or references to classes that implement IDisposable.
🔧 When Should You Use It?
You should implement the Disposable Pattern when your class:
Opens files or network connections
Uses database or service clients
Works with native memory or device handles
Manages other disposable objects
For example, Stream, HttpClient, DbConnection and FileStream all implement IDisposable and must be handled correctly.
🧩 Basic Implementation
public class FileLogger : IDisposable
{
private StreamWriter _writer;
private bool _disposed = false;
public FileLogger(string path)
{
_writer = new StreamWriter(path);
}
public void Log(string message)
{
if (_disposed) throw new ObjectDisposedException(nameof(FileLogger));
_writer.WriteLine(message);
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (_disposed) return;
if (disposing)
{
_writer?.Dispose();
}
_disposed = true;
}
~FileLogger()
{
Dispose(false);
}
}
This structure ensures both managed and unmanaged resources are cleaned up properly.
🧠 Why Use Dispose(bool disposing)?
The overloaded Dispose(bool disposing) lets you distinguish between:
true: Called by user code viaDispose()orusingfalse: Called by the garbage collector from the finalizer
This ensures you do not try to access managed objects during finalization.
🚀 Using using for Automatic Disposal
The using statement simplifies disposal:
using (var logger = new FileLogger("log.txt"))
{
logger.Log("Application started");
}
In .NET 6 and later, you can also use the using declaration:
using var logger = new FileLogger("log.txt");
logger.Log("App running");
This ensures disposal at the end of the scope without indentation or nesting.
🏗️ Disposable in ASP.NET Core
In ASP.NET Core, disposable services like DbContext or HttpClient are often managed by Dependency Injection (DI). Scoped and transient services are automatically disposed when the scope ends.
To register a disposable service:
services.AddScoped<IMyService, MyDisposableService>();
There is no need to manually call Dispose when using DI.
🚨 Common Mistakes to Avoid
Forgetting to call
Disposeon objects that hold resourcesNot using
GC.SuppressFinalize, which causes performance penaltiesManually disposing services managed by DI container
Using
IDisposableincorrectly in value types
✅ Summary
The Disposable Pattern ensures efficient resource management in .NET Core. Always implement it when handling unmanaged resources or other disposable objects. Use using or rely on DI to simplify cleanup. When applied properly, this pattern improves performance, prevents memory leaks and makes your applications more stable.
Understanding and using this pattern correctly is a key skill for any .NET developer aiming for clean and reliable code.