Communication
Result pattern for .NET that replaces exceptions with type-safe return values. Features railway-oriented programming, ASP.NET Core integration, RFC 7807 Problem Details, and built-in pagination. Designed for production systems requiring explicit error handling without the overhead of throwing exceptions.
Install / Use
/learn @managedcode/CommunicationREADME
ManagedCode.Communication
Result pattern for .NET that replaces exceptions with type-safe return values. Features railway-oriented programming, ASP.NET Core integration, RFC 7807 Problem Details, and built-in pagination. Designed for production systems requiring explicit error handling without the overhead of throwing exceptions.
Table of Contents
- Overview
- Key Features
- Installation
- Logging Configuration
- Core Concepts
- Quick Start
- API Reference
- Railway-Oriented Programming
- Command Pattern and Idempotency
- Error Handling Patterns
- Integration Guides
- Performance
- Comparison
- Best Practices
- Examples
- Migration Guide
Overview
ManagedCode.Communication brings functional error handling to .NET through the Result pattern. Instead of throwing exceptions, methods return Result types that explicitly indicate success or failure. This approach eliminates hidden control flow, improves performance, and makes error handling a first-class concern in your codebase.
Why Result Pattern?
Traditional exception handling has several drawbacks:
- Performance overhead: Throwing exceptions is expensive
- Hidden control flow: Exceptions create invisible exit points in your code
- Unclear contracts: Methods don't explicitly declare what errors they might produce
- Testing complexity: Exception paths require separate test scenarios
The Result pattern solves these issues by:
- Explicit error handling: Errors are part of the method signature
- Performance: No exception throwing overhead
- Composability: Chain operations using railway-oriented programming
- Type safety: Compiler ensures error handling
- Testability: All paths are explicit and easy to test
Key Features
🎯 Core Result Types
Result: Represents success/failure without a valueResult<T>: Represents success with valueTor failureCollectionResult<T>: Represents collections with built-in paginationProblem: RFC 7807 compliant error details
⚙️ Static Factory Abstractions
- Leverage C# static interface members to centralize factory overloads for every result, command, and collection type.
IResultFactory<T>andICommandFactory<T>deliver a consistent surface while bridge helpers remove repetitive boilerplate.- Extending the library now only requires implementing the minimal
Succeed/Failcontract—the shared helpers provide the rest.
🧭 Pagination Utilities
PaginationRequestencapsulates skip/take semantics, built-in normalization, and clamping helpers.PaginationOptionslets you define default, minimum, and maximum page sizes for a bounded API surface.PaginationCommandcaptures pagination intent as a first-class command with generated overloads for skip/take, page numbers, and enum command types.CollectionResult<T>.Succeed(..., PaginationRequest request, int totalItems)keeps result metadata aligned with pagination commands.
🚂 Railway-Oriented Programming
Complete set of functional combinators for composing operations:
Map: Transform success valuesBind/Then: Chain Result-returning operationsTap/Do: Execute side effectsMatch: Pattern matching on success/failureCompensate: Recovery from failuresMerge/Combine: Aggregate multiple results
🌐 Framework Integration
- ASP.NET Core: Automatic HTTP response mapping
- SignalR: Hub filters for real-time error handling
- Microsoft Orleans: Grain call filters and surrogates
- Command Pattern: Built-in command infrastructure with idempotency
🔍 Observability Built In
- Source-generated
LoggerCenterAPIs provide zero-allocation logging across ASP.NET Core filters, SignalR hubs, and command stores. - Call sites automatically check log levels, so you only pay for the logs you emit.
- Extend logging with additional
[LoggerMessage]partials to keep high-volume paths allocation free.
🛡️ Error Types
Pre-defined error categories with appropriate HTTP status codes:
- Validation errors (400 Bad Request)
- Not Found (404)
- Unauthorized (401)
- Forbidden (403)
- Internal Server Error (500)
- Custom enum-based errors
Installation
Package Manager Console
# Core library
Install-Package ManagedCode.Communication
# ASP.NET Core integration
Install-Package ManagedCode.Communication.AspNetCore
# Minimal API extensions
Install-Package ManagedCode.Communication.Extensions
# Orleans integration
Install-Package ManagedCode.Communication.Orleans
.NET CLI
# Core library
dotnet add package ManagedCode.Communication
# ASP.NET Core integration
dotnet add package ManagedCode.Communication.AspNetCore
# Minimal API extensions
dotnet add package ManagedCode.Communication.Extensions
# Orleans integration
dotnet add package ManagedCode.Communication.Orleans
PackageReference
<PackageReference Include="ManagedCode.Communication" Version="9.6.0" />
<PackageReference Include="ManagedCode.Communication.AspNetCore" Version="9.6.0" />
<PackageReference Include="ManagedCode.Communication.Extensions" Version="9.6.0" />
<PackageReference Include="ManagedCode.Communication.Orleans" Version="9.6.0" />
Logging Configuration
The library includes integrated logging for error scenarios. Configure logging to capture detailed error information:
ASP.NET Core Setup
var builder = WebApplication.CreateBuilder(args);
// Add your logging configuration
builder.Logging.AddConsole();
builder.Logging.AddDebug();
// Register other services
builder.Services.AddControllers();
// Configure Communication library - this enables automatic error logging
builder.Services.ConfigureCommunication();
var app = builder.Build();
Minimal API Result Mapping
Add the optional ManagedCode.Communication.Extensions package to bridge Minimal API endpoints with the Result pattern. The
package provides the ResultEndpointFilter and a fluent helper WithCommunicationResults that wraps the endpoint builder and
returns IResult instances automatically:
var builder = WebApplication.CreateBuilder(args);
builder.Services.ConfigureCommunication();
var app = builder.Build();
// Apply the filter to a single endpoint
app.MapGet("/orders/{id}", async (Guid id, IOrderService orders) =>
await orders.GetAsync(id))
.WithCommunicationResults();
// Or apply it to a group so every route inherits the conversion
app.MapGroup("/orders")
.WithCommunicationResults()
.MapPost(string.Empty, async (CreateOrder command, IOrderService orders) =>
await orders.CreateAsync(command));
app.Run();
Handlers can return any Result or Result<T> instance and the filter will reuse the existing ASP.NET Core converters so
you do not need to write manual IResult translations.
Resilient HTTP Clients
The extensions package also ships helpers that turn HttpClient calls directly into Result instances and optionally run
them through Polly resilience pipelines:
using ManagedCode.Communication.Extensions.Http;
using Polly;
using Polly.Retry;
var pipeline = new ResiliencePipelineBuilder<HttpResponseMessage>()
.AddRetry(new RetryStrategyOptions<HttpResponseMessage>
{
MaxRetryAttempts = 3,
Delay = TimeSpan.FromMilliseconds(200),
ShouldHandle = new PredicateBuilder<HttpResponseMessage>()
.HandleResult(response => !response.IsSuccessStatusCode)
})
.Build();
var result = await httpClient.SendForResultAsync<OrderDto>(
() => new HttpRequestMessage(HttpMethod.Get, $"/orders/{orderId}"),
pipeline);
if (result.IsSuccess)
{
// access result.Value without manually reading the HTTP payload
}
The helpers use the existing HttpResponseMessage converters, so non-success status codes automatically map to a
Problem with the response body and status code.
success responses map to 200 OK/204 No Content while failures become RFC 7807 problem details. Native Microsoft.AspNetCore.Http.IResult
responses pass through unchanged, so you can mix and match traditional Minimal API patterns with ManagedCode.Communication results.
Console Application Setup
var services = new ServiceCollection();
// Add logging
services.AddLogging(builder =>
{
builder.AddConsole()
.SetMinimumLevel(LogLevel.Information);
});
// Configure Communication library
services.ConfigureCommunication();
var serviceProvider = services.BuildServiceProvider();
The library automatically logs errors in Result factory methods (From, Try, etc.) with detailed context including file names, line numbers, and method names for easier debugging.
Core Concepts
Result Type
The Result type represents an operation that can either succeed or fail:
public struct Result
{
public bool IsSuccess { get; }
public Problem? Problem { get; }
}
Result Type with Value
The generic Result<T> includes a value on success:
public struct Result<T>
{
public bool IsSuccess { get; }
public T? Value { get; }
public Problem? Problem { get; }
}
Proble
Related Skills
diffs
337.7kUse the diffs tool to produce real, shareable diffs (viewer URL, file artifact, or both) instead of manual edit summaries.
clearshot
Structured screenshot analysis for UI implementation and critique. Analyzes every UI screenshot with a 5×5 spatial grid, full element inventory, and design system extraction — facts and taste together, every time. Escalates to full implementation blueprint when building. Trigger on any digital interface image file (png, jpg, gif, webp — websites, apps, dashboards, mockups, wireframes) or commands like 'analyse this screenshot,' 'rebuild this,' 'match this design,' 'clone this.' Skip for non-UI images (photos, memes, charts) unless the user explicitly wants to build a UI from them. Does NOT trigger on HTML source code, CSS, SVGs, or any code pasted as text.
openpencil
1.8kThe world's first open-source AI-native vector design tool and the first to feature concurrent Agent Teams. Design-as-Code. Turn prompts into UI directly on the live canvas. A modern alternative to Pencil.
animation-guide
A design system built with Base UI
