SkillAgentSearch skills...

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/Communication
About this skill

Quality Score

0/100

Category

Design

Supported Platforms

Universal

README

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.

NuGet License: MIT .NET

Table of Contents

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 value
  • Result<T>: Represents success with value T or failure
  • CollectionResult<T>: Represents collections with built-in pagination
  • Problem: 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> and ICommandFactory<T> deliver a consistent surface while bridge helpers remove repetitive boilerplate.
  • Extending the library now only requires implementing the minimal Succeed/Fail contract—the shared helpers provide the rest.

🧭 Pagination Utilities

  • PaginationRequest encapsulates skip/take semantics, built-in normalization, and clamping helpers.
  • PaginationOptions lets you define default, minimum, and maximum page sizes for a bounded API surface.
  • PaginationCommand captures 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 values
  • Bind / Then: Chain Result-returning operations
  • Tap / Do: Execute side effects
  • Match: Pattern matching on success/failure
  • Compensate: Recovery from failures
  • Merge / 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 LoggerCenter APIs 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

View on GitHub
GitHub Stars88
CategoryDesign
Updated11d ago
Forks2

Languages

C#

Security Score

100/100

Audited on Mar 15, 2026

No findings