♻️ 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()
orusing
false
: 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
Dispose
on objects that hold resourcesNot using
GC.SuppressFinalize
, which causes performance penaltiesManually disposing services managed by DI container
Using
IDisposable
incorrectly 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.