Source generators for REslava.Result library. Automatically generates extension methods to convert Result types to ASP.NET Core IResult with proper HTTP status codes and ProblemDetails.
$ dotnet add package REslava.Result.SourceGeneratorsZero-boilerplate ASP.NET endpoint generation — write business logic, Minimal API + MVC endpoints generate themselves.
This package contains 13 Roslyn source generators that eliminate ASP.NET boilerplate:
Minimal API
Result<T> to IResult with domain error-aware HTTP status codesOneOf<T1,...,T6> to IResult with tag-based + heuristic error mapping (arities 2–6)MVC Controllers
Result<T> to IActionResult with convention-based HTTP mappingOneOf<T1,...,T6> to IActionResult with domain error auto-mapping (arities 2–6)Cross-cutting
.Produces<T>(), .WithSummary(), .WithTags() with accurate error status codes.RequireAuthorization(), .AllowAnonymous() from attributes.Validate() extension methods from DataAnnotations; auto-injected by SmartEndpointsREslava.Result.FluentValidation) SmartEndpoints detects [FluentValidate] on body params and auto-injects IValidator<T> as a lambda parameter// Before: Manual endpoint registration (30+ lines per controller)
app.MapGet("/api/products", async (IProductService svc) => {
var result = await svc.GetProducts();
return result.Match(
products => Results.Ok(products),
errors => Results.BadRequest(errors));
}).WithName("GetProducts").WithTags("Products").Produces<List<Product>>(200).Produces(400);
app.MapGet("/api/products/{id}", async (int id, IProductService svc) => { /* ... */ });
app.MapPost("/api/products", async (CreateProductRequest req, IProductService svc) => { /* ... */ });
// ... repeat for every endpoint
// After: SmartEndpoints (just your business logic)
[AutoGenerateEndpoints(RoutePrefix = "/api/products")]
public class ProductService(AppDbContext db)
{
public async Task<Result<List<Product>>> GetProducts()
=> Result.Ok(await db.Products.ToListAsync());
public async Task<Result<Product>> GetProductById(int id)
=> await db.Products.FindAsync(id) is { } p
? Result.Ok(p)
: Result.Fail<Product>("Not found");
public async Task<Result<Product>> CreateProduct(CreateProductRequest request)
=> Result.Ok(db.Products.Add(new Product(request)).Entity);
}
// In Program.cs — one line:
app.MapProductServiceEndpoints();
dotnet add package REslava.Result
dotnet add package REslava.Result.SourceGenerators
using REslava.Result;
[AutoGenerateEndpoints(RoutePrefix = "/api/users")]
public class UserService(UserRepository repo)
{
public async Task<Result<User>> GetUserById(int id)
=> await repo.FindAsync(id) is { } user
? user // implicit conversion to Result<User>
: new NotFoundError($"User {id} not found");
}
// Program.cs
app.MapUserServiceEndpoints(); // auto-generated extension method
The generator infers:
Get* -> GET, Create*/Add* -> POST, Update* -> PUT, Delete* -> DELETE{id} parameters when methods have an id parameterCancellationToken cancellationToken = default.Validate() when request type carries [Validate]MIT License | .NET 8 / 9 / 10