### XML Documentation Example
Source: https://github.com/salihcantekin/unionrailway/blob/main/CONTRIBUTING.md
Example of XML documentation comments for a public API method, including type parameters and return values.
```csharp
///
/// Creates a successful rail carrying .
///
/// The type of the success value.
/// The success value to wrap.
/// A containing the success value.
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Rail Ok(T value) => value;
```
--------------------------------
### Full Chain Example with Union Railway Operations
Source: https://github.com/salihcantekin/unionrailway/blob/main/docs/index.html
An example combining Tap, Bind, Map, and Recover operations to build a complex asynchronous operation with error handling and fallback logic.
```csharp
// ── Full chain example ────────────────────────────────────────────────────
return await GetUserAsync(id)
.TapAsync(u => auditLog.LogAccessAsync(u.Id))
.BindAsync(u => GetPermissionsAsync(u.Id))
.MapAsync(perms => new UserProfile(perms))
.RecoverAsync(_ => UserProfile.Guest)
.ToHttpResultAsync();
```
--------------------------------
### xUnit Test Example
Source: https://github.com/salihcantekin/unionrailway/blob/main/CONTRIBUTING.md
Demonstrates a unit test following the Arrange, Act, Assert pattern for a successful rail creation.
```csharp
[Fact]
public void Ok_WithValue_ErrorIsNull()
{
// Arrange
var value = 42;
// Act
Rail result = Union.Ok(value);
// Assert
Assert.Null(result.Error);
Assert.True(result.TryGetValue(out var actual));
Assert.Equal(value, actual);
}
```
--------------------------------
### Installing UnionRailway Packages
Source: https://github.com/salihcantekin/unionrailway/blob/main/README.md
Command to add the necessary UnionRailway packages to a .NET project.
```bash
dotnet add package UnionRailway
dotnet add package UnionRailway.AspNetCore
dotnet add package UnionRailway.EntityFrameworkCore # Optional
```
--------------------------------
### C# Code Style Examples
Source: https://github.com/salihcantekin/unionrailway/blob/main/CONTRIBUTING.md
Illustrates preferred C# coding style for method implementations and async operations.
```csharp
// ✅ Good
public static Rail Ok(T value) => value;
public static async ValueTask> MapAsync(
this Rail result,
Func> mapper)
{
ArgumentNullException.ThrowIfNull(mapper);
// Implementation...
}
// ❌ Avoid
public static Rail Ok(T value)
{
return value;
}
```
--------------------------------
### AddRailway() DI Setup with Options
Source: https://github.com/salihcantekin/unionrailway/blob/main/README.md
Register all UnionRailway services with a single call, optionally configuring global ProblemDetails enrichment.
```csharp
builder.Services.AddRailway(options =>
{
// Global ProblemDetails enrichment (applied to ALL error responses)
options.ConfigureProblem = pd =>
pd.Extensions["traceId"] = Activity.Current?.Id;
});
```
--------------------------------
### Copy Install Command to Clipboard
Source: https://github.com/salihcantekin/unionrailway/blob/main/docs/index.html
JavaScript function to copy the 'dotnet add package UnionRailway' command to the user's clipboard. Provides visual feedback upon successful copy.
```javascript
function copyInstall(el) {
const text = 'dotnet add package UnionRailway';
navigator.clipboard.writeText(text).then(() => {
const hint = el.querySelector('.copy-hint');
const orig = hint.textContent;
hint.textContent = 'copied!';
hint.style.color = 'var(--accent2)';
setTimeout(() => {
hint.textContent = orig;
hint.style.color = '';
}, 1800);
});
}
```
--------------------------------
### Fetch User with LanguageExt Error Handling
Source: https://github.com/salihcantekin/unionrailway/blob/main/docs/COMPARISON.md
Example of fetching a user by ID using LanguageExt's Fin type and pattern matching for error handling.
```csharp
public async Task GetUser(int id)
{
Fin result = await userService.GetAsync(id);
return result.Match(
Succ: user => Results.Ok(user),
Fail: error => error.Code switch
{
404 => Results.NotFound(),
401 => Results.Unauthorized(),
_ => Results.Problem(error.Message)
}
);
}
```
--------------------------------
### UnionRailway Service Implementation
Source: https://github.com/salihcantekin/unionrailway/blob/main/README.md
Example of a service method returning `Rail`, demonstrating implicit conversion of a found user to a `Rail` and returning a specific `UnionError.NotFound`.
```csharp
public async ValueTask> GetUserAsync(int id)
{
var user = await db.Users.FindAsync(id);
if (user == null)
return new UnionError.NotFound("User");
return user; // ✅ Implicit conversion
}
```
--------------------------------
### Global Exception Handling Setup
Source: https://github.com/salihcantekin/unionrailway/blob/main/README.md
Enable global exception handling for all endpoints by adding UseRailwayExceptionHandler early in the middleware pipeline. This ensures consistent RFC 7807 error responses.
```csharp
var app = builder.Build();
app.UseRailwayExceptionHandler(); // Add early in pipeline
app.UseAuthentication();
app.UseAuthorization();
```
--------------------------------
### Fetch User with ErrorOr Error Handling
Source: https://github.com/salihcantekin/unionrailway/blob/main/docs/COMPARISON.md
Example of fetching a user by ID using ErrorOr and its Match method for error handling.
```csharp
public async Task GetUser(int id)
{
ErrorOr result = await userService.GetAsync(id);
return result.Match(
value => Results.Ok(value),
errors => errors[0].Type switch
{
ErrorType.NotFound => Results.NotFound(),
ErrorType.Unauthorized => Results.Unauthorized(),
_ => Results.Problem(errors[0].Description)
}
);
}
```
--------------------------------
### Fetch User with UnionRailway HTTP Integration
Source: https://github.com/salihcantekin/unionrailway/blob/main/docs/COMPARISON.md
Example of fetching a user by ID using UnionRailway, demonstrating its automatic RFC 7807 HTTP result mapping.
```csharp
public async Task GetUser(int id)
{
var result = await userService.GetAsync(id);
return result.ToHttpResult(); // ✅ Automatic RFC 7807 mapping
}
```
--------------------------------
### Custom Error Mapper Implementation
Source: https://github.com/salihcantekin/unionrailway/blob/main/docs/index.html
Provides an example of a custom error mapper that implements `IUnionErrorMapper` to define specific HTTP responses for different error types.
```csharp
// ── Option C: Custom error mapper ───────────────────────────────────────
public class CustomErrorMapper : IUnionErrorMapper
{
public IResult? TryMap(UnionError error) => error.Value switch
{
UnionError.NotFound nf => Results.Problem(
detail: $"Could not locate '{nf.Resource}'.",
statusCode: 404, title: "Resource Not Found"),
UnionError.Custom { Code: "RATE_LIMIT" } c => Results.Problem(
detail: c.Message, statusCode: 429, title: "Rate Limited"),
_ => null // fall back to default RFC 7807 mapping
};
}
```
--------------------------------
### AddRailway() DI Setup with Custom Mapper
Source: https://github.com/salihcantekin/unionrailway/blob/main/README.md
Register UnionRailway services with a custom error mapper and optional configuration.
```csharp
// Or with a custom mapper:
builder.Services.AddRailway(options => ...);
```
--------------------------------
### HttpClient GetFromJsonAsUnionAsync
Source: https://github.com/salihcantekin/unionrailway/blob/main/README.md
Perform an HTTP GET request and automatically map the JSON response to a Rail type. Handles success (2xx) and error (4xx/5xx) responses.
```csharp
var result = await httpClient.GetFromJsonAsUnionAsync("/users/42");
// Automatic mapping: 2xx → Success, 4xx/5xx → Error
```
--------------------------------
### UnionRailway Endpoint Filter for Zero-Boilerplate APIs
Source: https://github.com/salihcantekin/unionrailway/blob/main/docs/index.html
This example shows how to use UnionRailway's endpoint filter to automatically handle `Rail` results. The `Rail` can be returned directly from the endpoint handler without manual conversion to `IResult`.
```csharp
// Or zero-boilerplate with the endpoint filter:
var api = app.MapGroup("/api").WithRailwayFilter();
api.MapGet("/users/{id}",
async (int id, UserService svc) =>
await svc.GetUserAsync(id)); // Rail returned directly!
```
--------------------------------
### Run Benchmarks
Source: https://github.com/salihcantekin/unionrailway/blob/main/CONTRIBUTING.md
Navigate to the benchmarks directory and run the performance benchmarks in release mode.
```bash
cd tests/UnionRailway.Benchmarks
dotnet run -c Release
```
--------------------------------
### Restore and Build Solution
Source: https://github.com/salihcantekin/unionrailway/blob/main/CONTRIBUTING.md
Restore project dependencies and build the entire solution.
```bash
dotnet restore
dotnet build
```
--------------------------------
### HTTP GET Request with Union Railway
Source: https://github.com/salihcantekin/unionrailway/blob/main/docs/index.html
Performs an HTTP GET request and deserializes the JSON response into a UserDto, mapping common HTTP status codes to Union Railway error types.
```csharp
// Install: dotnet add package UnionRailway.HttpClient
// ── GET ──────────────────────────────────────────────────────────────────
Rail result = await httpClient
.GetFromJsonAsUnionAsync("/users/42");
// Automatic mapping:
// 2xx → Rail with the deserialized body
// 404 → UnionError.NotFound
// 401 → UnionError.Unauthorized
// 403 → UnionError.Forbidden
// 409 → UnionError.Conflict
// 422 → UnionError.Validation
// 5xx → UnionError.SystemFailure
```
--------------------------------
### Run Unit Tests
Source: https://github.com/salihcantekin/unionrailway/blob/main/CONTRIBUTING.md
Execute all unit tests in the solution.
```bash
dotnet test
```
--------------------------------
### Configuring Union Railway DI
Source: https://github.com/salihcantekin/unionrailway/blob/main/docs/index.html
Demonstrates how to set up dependency injection for Union Railway, including global problem details enrichment and custom error mappers.
```csharp
// One-line DI setup
builder.Services.AddRailway(options =>
{
// Global ProblemDetails enrichment — applied to ALL error responses
options.ConfigureProblem = pd =>
pd.Extensions["traceId"] = Activity.Current?.Id;
});
// Or with a custom mapper:
builder.Services.AddRailway();
```
--------------------------------
### SystemFailure Constructor
Source: https://github.com/salihcantekin/unionrailway/blob/main/README.md
Illustrates creating SystemFailure errors with just a message or with both a message and an inner exception.
```csharp
// Message only (wraps in InvalidOperationException internally):
var sf = new UnionError.SystemFailure("Database connection lost");
// Message with inner exception:
var sf = new UnionError.SystemFailure("Operation failed", innerException);
```
--------------------------------
### Create Rail Success or Failure
Source: https://github.com/salihcantekin/unionrailway/blob/main/README.md
Demonstrates creating a Rail using implicit conversion from a ValueTask or explicit creation with Union.Ok or Union.Fail.
```csharp
public ValueTask> GetUserAsync(int id)
{
// Option 1: Implicit conversion
return user;
// Option 2: Explicit creation
return Union.Ok(user);
return Union.Fail(new UnionError.NotFound("User"));
}
```
--------------------------------
### LanguageExt Approach to Handling Results
Source: https://github.com/salihcantekin/unionrailway/blob/main/docs/COMPARISON.md
Demonstrates how to handle a `Fin` result from LanguageExt using pattern matching to return an HTTP response.
```csharp
using LanguageExt;
using LanguageExt.Common;
Fin result = await GetUserAsync(id);
return result.Match(
Succ: user => Results.Ok(user),
Fail: error => Results.Problem(error.Message)
);
```
--------------------------------
### Explicit Union Creation Helpers
Source: https://github.com/salihcantekin/unionrailway/blob/main/docs/index.html
Shows how to explicitly create success and failure `Rail` instances using static helper methods.
```csharp
var ok = Union.Ok(new User { Id = 1 });
var fail = Union.Fail(new UnionError.NotFound("User"));
```
--------------------------------
### Benchmark Template
Source: https://github.com/salihcantekin/unionrailway/blob/main/CONTRIBUTING.md
Use this template when adding performance benchmarks for new operations. Ensure to include a descriptive name and memory diagnostics.
```csharp
[Benchmark(Description = "Your operation")]
[MemoryDiagnoser]
public Rail YourOperation()
{
// Your code
}
```
--------------------------------
### Create Feature Branch
Source: https://github.com/salihcantekin/unionrailway/blob/main/CONTRIBUTING.md
Create a new branch for your feature development.
```bash
git checkout -b feature/your-feature-name
```
--------------------------------
### Pattern Matching Rail Results
Source: https://github.com/salihcantekin/unionrailway/blob/main/docs/index.html
Illustrates different styles of pattern matching to handle the results of a Rail operation. The recommended style uses an early return with IsSuccess.
```csharp
Rail result = await service.GetUserAsync(id);
// Style A: IsSuccess out-parameter (early return, recommended)
if (!result.IsSuccess(out var user, out var error))
return error.GetValueOrDefault().ToHttpResult();
Console.WriteLine(user.Name);
// Style B: Match
return result.Match(
onOk: u => Results.Ok(u),
onError: err => err.ToHttpResult());
// Style C: Error property check
if (result.Error is not null)
return result.Error.GetValueOrDefault().ToHttpResult();
```
--------------------------------
### Migration from LanguageExt to UnionRailway
Source: https://github.com/salihcantekin/unionrailway/blob/main/docs/COMPARISON.md
Shows how to migrate code from LanguageExt's Fin type to UnionRailway's Rail type, simplifying error handling.
```csharp
// Before: LanguageExt
Fin result = await repo.GetAsync(id);
var user = result.Match(
Succ: u => u,
Fail: _ => throw new Exception()
);
// After: UnionRailway
Rail result = await repo.GetAsync(id);
var user = result.Unwrap(); // or .Match()
```
--------------------------------
### Clone Repository
Source: https://github.com/salihcantekin/unionrailway/blob/main/CONTRIBUTING.md
Clone your fork of the UnionRailway repository locally.
```bash
git clone https://github.com/YOUR_USERNAME/unionrailway.git
cd unionrailway
```
--------------------------------
### Bind Operation for Chaining Operations
Source: https://github.com/salihcantekin/unionrailway/blob/main/docs/index.html
Illustrates the Bind operation for chaining operations that may also fail. It sequentially executes operations, passing the successful result to the next operation.
```csharp
// ── Bind: chain operations that may also fail ────────────────────────────
Rail summary =
await GetUserAsync(id) // Rail
.BindAsync(u => GetOrdersAsync(u.Id)) // Rail
.MapAsync(orders => new OrderSummary(orders)); // Rail
```
--------------------------------
### Run Tests with Coverage
Source: https://github.com/salihcantekin/unionrailway/blob/main/CONTRIBUTING.md
Execute tests and collect code coverage data using the specified collector.
```bash
dotnet test --collect:"XPlat Code Coverage"
```
--------------------------------
### Zero-Boilerplate Endpoints with .WithRailwayFilter()
Source: https://github.com/salihcantekin/unionrailway/blob/main/docs/index.html
Demonstrates using `.WithRailwayFilter()` to automatically handle `Rail` results in ASP.NET Core endpoints, simplifying response mapping.
```csharp
// ── Option B: Zero-boilerplate endpoint filter ───────────────────────────
var api = app.MapGroup("/api").WithRailwayFilter();
api.MapGet("/users/{id}",
async (int id, UserService svc) =>
await svc.GetUserAsync(id)); // Rail → 200 / 404 auto
api.MapDelete("/users/{id}",
async (int id, UserService svc) =>
await svc.DeleteAsync(id)); // Rail → 204 auto
```
--------------------------------
### Chaining HTTP Requests with BindAsync
Source: https://github.com/salihcantekin/unionrailway/blob/main/docs/index.html
Chains multiple HTTP requests using BindAsync. It first fetches a user and then fetches their orders, finally mapping the result to an OrderSummary.
```csharp
// ── Chaining with the result ─────────────────────────────────────────────
var summary = await httpClient
.GetFromJsonAsUnionAsync("/users/42")
.BindAsync(u => httpClient.GetFromJsonAsUnionAsync($"/orders?userId={u.Id}"))
.MapAsync(orders => new OrderSummary(orders.Length));
return summary.ToHttpResult();
```
--------------------------------
### Pattern Matching on Rail
Source: https://github.com/salihcantekin/unionrailway/blob/main/README.md
Illustrates three styles of pattern matching on a Rail result: using IsSuccess, Match, or checking the Error property.
```csharp
// Style 1: IsSuccess pattern
if (!result.IsSuccess(out var user, out var error))
return error.GetValueOrDefault().ToHttpResult();
// Style 2: Match
return result.Match(
onOk: user => Results.Ok(user),
onError: error => error.ToHttpResult());
// Style 3: Error property check
if (result.Error is not null)
return result.Error.GetValueOrDefault().ToHttpResult();
```
--------------------------------
### Returning Rail from Service Methods
Source: https://github.com/salihcantekin/unionrailway/blob/main/docs/index.html
Demonstrates how to return Rail from service methods, handling both successful results and explicit errors. Implicit conversion to Rail is supported for success types.
```csharp
public class UserService
{
public async ValueTask> GetUserAsync(int id)
{
var user = await db.Users.FindAsync(id);
if (user == null)
return new UnionError.NotFound("User"); // explicit error
return user; // implicit conversion ✅
}
public async ValueTask> DeleteUserAsync(int id)
{
var user = await db.Users.FindAsync(id);
if (user == null)
return new UnionError.NotFound("User");
db.Users.Remove(user);
await db.SaveChangesAsync();
return Unit.Value; // 204 No Content
}
}
```
--------------------------------
### Simplified Service Method with UnionRailway
Source: https://github.com/salihcantekin/unionrailway/blob/main/docs/index.html
This service method uses UnionRailway's `FirstOrDefaultAsUnionAsync` to fetch a user, returning a `Rail` type. This eliminates the need for explicit null checks and exception handling within the service.
```csharp
// Service method — one line
public async ValueTask> GetUserAsync(int id)
=> await db.Users
.FirstOrDefaultAsUnionAsync("User", x => x.Id == id);
```
--------------------------------
### UnionRailway vs. Exceptions Comparison
Source: https://github.com/salihcantekin/unionrailway/blob/main/README.md
Highlights the advantages of UnionRailway over traditional exception handling by showing explicit type safety and performance benefits.
```csharp
// ❌ Exceptions: Slow, unclear, unsafe
try { var user = await repo.GetAsync(id); }
catch (NotFoundException) { return Results.NotFound(); }
catch (UnauthorizedException) { return Results.Unauthorized(); }
// What other exceptions can this throw? 🤷
// ✅ UnionRailway: Fast, explicit, type-safe
var result = await repo.GetAsync(id);
return result.ToHttpResult();
// Compiler knows: Success | NotFound | Unauthorized ✅
```
--------------------------------
### FluentResults Approach to Handling Results
Source: https://github.com/salihcantekin/unionrailway/blob/main/docs/COMPARISON.md
Demonstrates handling a `Result` from FluentResults by checking for failure and returning an appropriate HTTP response.
```csharp
using FluentResults;
Result result = await GetUserAsync(id);
if (result.IsFailed)
{
var error = result.Errors.First();
return Results.Problem(error.Message);
}
return Results.Ok(result.Value);
```
--------------------------------
### EF Core SaveChangesAsUnionAsync
Source: https://github.com/salihcantekin/unionrailway/blob/main/docs/index.html
Placeholder for demonstrating the `SaveChangesAsUnionAsync` method from Entity Framework Core integration.
```csharp
// ── SaveChangesAsUnionAsync ──────────────────────────────────────────────
```
--------------------------------
### OneOf Approach to Handling Discriminated Unions
Source: https://github.com/salihcantekin/unionrailway/blob/main/docs/COMPARISON.md
Shows how to handle a `OneOf` result from OneOf by matching on the possible types to return an HTTP response.
```csharp
using OneOf;
OneOf result = await GetUserAsync(id);
return result.Match(
user => Results.Ok(user),
notFound => Results.NotFound(),
serverError => Results.Problem(serverError.Message)
);
```
--------------------------------
### Customizing ProblemDetails
Source: https://github.com/salihcantekin/unionrailway/blob/main/README.md
Post-process ProblemDetails responses to add trace IDs or strip details in production.
```csharp
return result.ToHttpResult(configureProblem: pd =>
{
pd.Extensions["traceId"] = Activity.Current?.Id;
if (env.IsProduction())
pd.Detail = "An error occurred.";
});
```
--------------------------------
### Switch - Void Match for Side Effects
Source: https://github.com/salihcantekin/unionrailway/blob/main/README.md
Demonstrates using Switch for executing side effects on success or error branches without returning a value, including an async version.
```csharp
result.Switch(
onOk: user => logger.LogInformation("Found user {Id}", user.Id),
onError: err => logger.LogWarning("Failed: {Error}", err));
// Async version:
await resultTask.SwitchAsync(
onOk: user => { logger.LogInformation("Found user {Id}", user.Id); return Task.CompletedTask; },
onError: err => { logger.LogWarning("Failed: {Error}", err); return Task.CompletedTask; });
```
--------------------------------
### Current UnionRailway Implementation Structure
Source: https://github.com/salihcantekin/unionrailway/blob/main/README.md
Illustrates the current struct-based implementation of Rail and UnionError for .NET 8 and .NET 11 Preview.
```csharp
[Union] // High-performance struct-based implementation
public readonly struct Rail { /* ... */ }
public readonly struct UnionError { /* ... */ }
```
--------------------------------
### UnionRailway Error Handling for Services
Source: https://github.com/salihcantekin/unionrailway/blob/main/README.md
Demonstrates how to use UnionRailway to return a type-safe `Rail` from a service method, replacing exceptions with explicit return types.
```csharp
public async ValueTask> GetUserAsync(int id)
{
return await db.Users.FirstOrDefaultAsUnionAsync("User", x => x.Id == id);
}
```
--------------------------------
### Wrapping Legacy Code with Exception Handling
Source: https://github.com/salihcantekin/unionrailway/blob/main/docs/index.html
Wraps legacy code that might throw exceptions using UnionWrapper.RunAsync, converting any exception into a UnionError.SystemFailure.
```csharp
// ── Wrap exception-based legacy code ─────────────────────────────────────
Rail result = await UnionWrapper.RunAsync(
() => legacyReportService.GenerateAsync(reportId));
// Any exception → UnionError.SystemFailure(ex)
```
--------------------------------
### Use Union.Ok(object) for Explicit Boxing
Source: https://github.com/salihcantekin/unionrailway/blob/main/README.md
When boxing to object, use the explicit Union.Ok(object) overload to prevent potential type inference issues.
```csharp
// ✅ GOOD: Explicit object overload prevents inference issues
Rail