$npx -y skills add managedcode/dotnet-skills --skill managedcode-communicationUse ManagedCode.Communication when a .NET application needs explicit result objects, structured errors, and predictable service or API boundaries instead of exception-driven control flow. USE FOR: integrating ManagedCode.Communication into services or APIs; replacing exception-dr
| 1 | # ManagedCode.Communication |
| 2 | |
| 3 | ## Trigger On |
| 4 | |
| 5 | - integrating `ManagedCode.Communication` into services or APIs |
| 6 | - replacing exception-driven result handling with explicit results |
| 7 | - reviewing service boundaries that return success or failure payloads |
| 8 | - documenting result-pattern usage across ASP.NET Core or application services |
| 9 | - mapping application errors to RFC 7807 problem details, Minimal API results, SignalR filters, or Orleans call filters |
| 10 | |
| 11 | ## Install |
| 12 | |
| 13 | Use the package that matches the boundary. Current upstream release reviewed: `v10.0.4`. |
| 14 | |
| 15 | ```bash |
| 16 | dotnet add package ManagedCode.Communication |
| 17 | dotnet add package ManagedCode.Communication.AspNetCore |
| 18 | dotnet add package ManagedCode.Communication.Extensions |
| 19 | dotnet add package ManagedCode.Communication.Orleans |
| 20 | ``` |
| 21 | |
| 22 | For pinned project files: |
| 23 | |
| 24 | ```xml |
| 25 | <PackageReference Include="ManagedCode.Communication" Version="10.0.4" /> |
| 26 | <PackageReference Include="ManagedCode.Communication.AspNetCore" Version="10.0.4" /> |
| 27 | <PackageReference Include="ManagedCode.Communication.Extensions" Version="10.0.4" /> |
| 28 | <PackageReference Include="ManagedCode.Communication.Orleans" Version="10.0.4" /> |
| 29 | ``` |
| 30 | |
| 31 | ## Workflow |
| 32 | |
| 33 | 1. Confirm the boundary where the library belongs: |
| 34 | - service result contracts |
| 35 | - application manager boundaries |
| 36 | - API endpoints that translate results into HTTP responses |
| 37 | 2. Keep result creation and error mapping explicit instead of mixing exceptions, nulls, and ad-hoc tuples. |
| 38 | 3. Pattern-match result objects at the boundary that converts them into user-facing responses. |
| 39 | 4. Do not hide domain failures behind generic success wrappers. |
| 40 | 5. Configure framework integration only where it removes manual translation: |
| 41 | - `ConfigureCommunication()` for ASP.NET Core logging and converters |
| 42 | - `WithCommunicationResults()` for Minimal API endpoint or group conversion |
| 43 | - Orleans or SignalR packages only when those runtime filters are actually in use |
| 44 | 6. Validate positive, negative, and error-path handling after integration. |
| 45 | |
| 46 | ```mermaid |
| 47 | flowchart LR |
| 48 | A["Domain or service operation"] --> B["ManagedCode.Communication result"] |
| 49 | B --> C["Application or API boundary"] |
| 50 | C --> D["HTTP response or caller-visible contract"] |
| 51 | ``` |
| 52 | |
| 53 | ## Practical Usage |
| 54 | |
| 55 | ### Read path with explicit failures |
| 56 | |
| 57 | ```csharp |
| 58 | public sealed class OrderService(IOrderRepository orders) |
| 59 | { |
| 60 | public async Task<Result<OrderDto>> GetAsync(Guid id, CancellationToken ct) |
| 61 | { |
| 62 | var order = await orders.FindAsync(id, ct); |
| 63 | |
| 64 | return order is null |
| 65 | ? Result<OrderDto>.FailNotFound($"Order {id} was not found.") |
| 66 | : Result<OrderDto>.Succeed(OrderDto.From(order)); |
| 67 | } |
| 68 | } |
| 69 | ``` |
| 70 | |
| 71 | Use this shape when absence, validation, authorization, or domain rejection is an expected outcome. Reserve exceptions for unexpected infrastructure faults. |
| 72 | |
| 73 | ### Write path through Minimal APIs |
| 74 | |
| 75 | ```csharp |
| 76 | var builder = WebApplication.CreateBuilder(args); |
| 77 | |
| 78 | builder.Services.ConfigureCommunication(); |
| 79 | |
| 80 | var app = builder.Build(); |
| 81 | |
| 82 | app.MapGroup("/orders") |
| 83 | .WithCommunicationResults() |
| 84 | .MapPost(string.Empty, async (CreateOrder command, OrderService orders, CancellationToken ct) => |
| 85 | await orders.CreateAsync(command, ct)); |
| 86 | ``` |
| 87 | |
| 88 | Handlers can return `Result` or `Result<T>` and let the extension package map failures to HTTP results and problem details at the API boundary. |
| 89 | |
| 90 | ### Compose validation and domain steps |
| 91 | |
| 92 | ```csharp |
| 93 | public async Task<Result<OrderReceipt>> CreateAsync(CreateOrder command, CancellationToken ct) |
| 94 | { |
| 95 | var validation = Validate(command); |
| 96 | if (validation.IsFailed) |
| 97 | { |
| 98 | return Result<OrderReceipt>.Fail(validation.Problem!); |
| 99 | } |
| 100 | |
| 101 | return await Result<Order>.From(() => BuildOrder(command)) |
| 102 | .ThenAsync(order => SaveAsync(order, ct)) |
| 103 | .Then(order => Result<OrderReceipt>.Succeed(new OrderReceipt(order.Id, order.CreatedAt))); |
| 104 | } |
| 105 | ``` |
| 106 | |
| 107 | Use railway-style composition when each step can return a result and the caller should stop at the first real failure. |
| 108 | |
| 109 | ## Options And Constraints |
| 110 | |
| 111 | - `Result`, `Result<T>`, `CollectionResult<T>`, and `Problem` are the core surfaces. Keep them at service/API boundaries rather than leaking framework-specific HTTP results into domain code. |
| 112 | - `CollectionResult<T>` plus `PaginationRequest` / `PaginationOp |