A thread safe, async safe context management system with built-in security boundaries for .NET applications.
- Thread-Safe & Async-Safe - Built on
AsyncLocal<T>for automatic context isolation - Security Boundaries - Defensive copy pattern prevents untrusted code from accessing sensitive data
- Multi-Tenant Ready - Perfect for SaaS applications requiring tenant isolation
- Plugin-Friendly - Safe context exposure to third-party plugins
- Distributed Tracing - Built-in support for correlation IDs and trace context
- High Performance - Minimal overhead (~100ns per operation)
using ModularityKit.Context.Abstractions;
using ModularityKit.Context.AspNet;
// 1. Define your context
public class MyContext : IContext
{
public string Id { get; }
public DateTimeOffset CreatedAt { get; }
public string UserId { get; }
public string TenantId { get; }
}
// 2. Register in DI
services.AddContext();
// 3. Use in your code
public class OrderService(IContextAccessor<MyContext> context)
{
public void ProcessOrder()
{
var ctx = context.RequireCurrent();
Console.WriteLine($"Processing for user: {ctx.UserId}");
}
}
// 4. Execute with context
var context = new MyContext("ctx-1", "user-123", "tenant-456");
await contextManager.ExecuteInContext(context, async () =>
{
orderService.ProcessOrder();
});public class OrderService
{
// Passing context everywhere - painful!
public async Task CreateOrder(string userId, string tenantId, string correlationId)
{
await ValidateOrder(userId, tenantId, correlationId);
await ProcessPayment(userId, tenantId, correlationId);
await SendEmail(userId, tenantId, correlationId);
}
}public class OrderService(IContextAccessor<MyContext> context)
{
// Clean API - context flows automatically
public async Task CreateOrder()
{
await ValidateOrder(); // Context flows automatically
await ProcessPayment();
await SendEmail();
}
}- Installation & Setup - Complete setup guide
- Basic Usage - Learn the fundamentals
- Core Concepts - Understanding the architecture
- Multi-Tenant Applications - Building SaaS applications
- API Reference - Complete API documentation
- Best Practices - Tips and recommendations
public class DocumentService(IContextAccessor<MyContext> context)
{
public async Task GetDocument(string documentId)
{
var ctx = context.RequireCurrent();
// Automatic tenant filtering
return await _db.Documents
.Where(d => d.TenantId == ctx.TenantId)
.Where(d => d.Id == documentId)
.FirstOrDefaultAsync();
}
}Automatic tenant isolation using
IContextAccessorensures security and data separation.
Application Layer
├─ Trusted Code (Full Access)-> IContextAccessor<MyContext>
└─ Untrusted Code (Read-Only) -> IContextAccessor<IReadOnlyContext>
│
▼
Context Infrastructure
├─ ContextStore (AsyncLocal)
├─ ContextAccessor
└─ ContextManager
│
▼
Security Boundary
└─ ReadOnlyContextSnapshot (Defensive Copy)
Learn more about architecture →
- Create context per operation (request/job)
- Use
RequireCurrent()when context is expected - Let
ExecuteInContexthandle cleanup - Treat contexts as immutable
- Share context across operations
- Mutate context properties
- Use
Currentwithout null check - Store context in static fields
Read full best practices guide →
- IContext - Base context interface
- IContextAccessor<TContext> - Access current context
- IContextManager<TContext> - Manage context lifecycle
- AddContext<TContext>() - Register context infrastructure
- AddReadOnlyContextAccessor<TContext>() - Register read-only accessor
Built with ❤️ for .NET developers