EZ.MinimalApi.Generator 1.3.0

dotnet add package EZ.MinimalApi.Generator --version 1.3.0
                    
NuGet\Install-Package EZ.MinimalApi.Generator -Version 1.3.0
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="EZ.MinimalApi.Generator" Version="1.3.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="EZ.MinimalApi.Generator" Version="1.3.0" />
                    
Directory.Packages.props
<PackageReference Include="EZ.MinimalApi.Generator" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add EZ.MinimalApi.Generator --version 1.3.0
                    
#r "nuget: EZ.MinimalApi.Generator, 1.3.0"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package EZ.MinimalApi.Generator@1.3.0
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=EZ.MinimalApi.Generator&version=1.3.0
                    
Install as a Cake Addin
#tool nuget:?package=EZ.MinimalApi.Generator&version=1.3.0
                    
Install as a Cake Tool

EZ.MinimalApi.Generator

EZ.MinimalApi.Generator is a C# Source Generator that automatically maps Minimal API endpoints using attributes.
It allows developers to organize their API endpoints in clean classes, without manually writing MapGet, MapPost, etc.

This library focuses on:

  • Automatic endpoint registration
  • Inline method-body generation (your method code becomes the request delegate)
  • Support for HTTP verbs, groups, filters, authorization, tags, and route names
  • Zero runtime dependencies (compile-time only)

Where to use?

Some attributes can only be used at class level ([C]), method level ([M]) or both ([C|M]).

โœจ Features

  • Get, Post, Put, Patch, Delete, Fallback attributes for routing
  • Endpoint attribute to register endpoint classes
  • Automatic group mapping via GroupEndpoint
  • Inline delegate generation (no instance creation required)
  • Supports:
    • Authorization with: policies, IAuthorizeData types, and AuthorizationPolicy
    • Route naming with: Name, Summary, Description and DisplayName
    • Filters
    • Tags
    • Accepts
    • AllowAnonymous
    • Produces / ProducesProblem
    • Cors
    • ExcludeFromDescription
    • Rate Limiting (EnableRateLimiting / DisableRateLimiting)
    • Output Caching (CacheOutput / DisableOutputCache)
    • Request Size Limit (RequestSizeLimit / DisableRequestSizeLimit)
    • Endpoint Group Name
    • SkipStatusCodePages
    • Request Timeout (RequestTimeout / DisableRequestTimeout)
  • Fully compile-time, no reflection

๐Ÿ“ Sample Project

A complete sample project is available at samples/EZ.MinimalApi.Sample demonstrating all attributes in a real Minimal API application.

Run it with:

dotnet run --project samples/EZ.MinimalApi.Sample

Tests are in tests/EZ.MinimalApi.Generator.Tests with 9+ test cases covering endpoint generation, attributes, and compilation validation:

dotnet test tests/EZ.MinimalApi.Generator.Tests

๐Ÿ“ฆ Installation

Install via NuGet:

dotnet add package EZ.MinimalApi.Generator

Or via Package Manager

Install-Package EZ.MinimalApi.Generator

๐Ÿš€ Getting Started

1 - Mark a static class with [Endpoint]

namespace MyAwesomeApi.Endpoints;

[Endpoint]
public static class UserEndpoints
{
    [Get]
    public static IResult GetById() =>
        Results.Ok();

    [Post]
    public static IResult CreateUser() =>
        Results.Created();
}
  1. Call the generated extension method in Program.cs
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();

app.MapCustomEndpoints(); // Generated automatically

app.Run();

Generated Output

The code above will produce:

Aggregator class that wraps all the generated endpoints in one method call.

namespace Microsoft.AspNetCore.Builder
{
	public static class WebApplicationAggregatorExtensions
	{
		public static WebApplication MapCustomEndpoints(this WebApplication app)
		{
			EZ.MinimalApi.GeneratedEndpoints.UserEndpointsExtensions.MapUserEndpoints(app);
			
			return app;
		}
	}
}

And the class that maps all endpoints.

namespace EZ.MinimalApi.GeneratedEndpoints
{
	public static class UserEndpointsExtensions
	{
		public static WebApplication MapUserEndpoints(this WebApplication app)
		{
			app.MapGet("/{id}", MyAwesomeApi.Endpoints.UserEndpoints.GetUserById);

			return app;
		}
	}
}

Grouping<sup>[C]</sup>

[Endpoint]
[GroupEndpoint("/users")]
public static class UserEndpoints
{
    [Get("/{id}")]
    public static IResult Get(Guid id, IUserRepository repo) => 
        Results.Ok();

    [Post]
    public static IResult Create() => 
        Results.Created();
}

Generated:

var group = app.MapGroup("/users");

group.MapGet("/{id}", ...);
group.MapPost("/", ...);

Authorization<sup>[C|M]</sup>

[Get("/admin")]
[Authorization("AdminPolicy")] //By policy name
[Authorization("Admin", "SuperUser")] //Multiple policies
[Authorization(typeof(MyCustomAuthorizeData))] //IAuthorizeData types
[Authorization(typeof(AdminPolicy))] //AuthorizationPolicy type
public static IResult GetAdmin() => 
    Results.Ok();

Generated:

app.MapGet("/admin", ...)
    .RequireAuthorization("AdminPolicy");
//(or the appropriate overload)

Filters<sup>[C|M]</sup>

Filters can be applied in two places:

  • Class-level filters โ†’ Applied to the group
  • Method-level filters โ†’ Applied to individual endpoints
[Endpoint]
[GroupEndpoint("/users")]
[Filter<GlobalFilter>]      // applied to the group
public static class UserEndpoints
{
    [Get]
    [Filter<EndpointFilter>] // applied only to this endpoint
    public static IResult Get() =>
        Results.Ok();
}

Generated:

var group = app.MapGroup("/users")
    .AddEndpointFilter<GlobalFilter>();

group.MapGet("/{id}", ...)
    .AddEndpointFilter<EndpointFilter>();

Tags<sup>[C|M]</sup>

Can be used at class level or method level

[Get]
[Tags("Users", "Read")]
public static IResult Get() =>
    Results.Ok();

Generated:

app.MapGet("/", ...)
    .WithTags("Users", "Read");

Route Names<sup>[C|M]</sup>

Can be used at class level or method level

[Get]
[Name("Get user by ID")]
[DisplayName("GetUserById")]
[Description("Get user information by ID")]
[Summary("Gets user information by ID or returns 404 if not found")]
public static IResult Get() =>
    Results.Ok();

Generated:

app.MapGet("/", ...)
    .WithName("GetUserById")
    .WithDisplayName("GetUserById")
    .WithDescription("Get user information by ID")
    .WithSummary("Gets user information by ID or returns 404 if not found");

Accepts<sup>[M]</sup>

Specifies which content-type will be accepted based on the type of request body. Can be used multiple times.

[Get]
[Accpets<User>("application/json")]
//or [Accepts(typeof(User), "application/json")]
public static IResult Get() =>
    Results.Ok();

Generated:

app.MapGet("/", ...)
    .Accepts<User>("application/json");

AllowAnonymous<sup>[C|M]</sup>

Specifies if the group or endpoint can be accessed without authentication/authorization

[Get]
[AllowAnonymous]
public static IResult Get() =>
    Results.Ok();

Generated:

ap.MapGet("/", ...)
    .AllowAnonymous();

Fallback<sup>[M]</sup>

Maps a catch-all route for requests that don't match any other endpoint. When no route is specified, it generates MapFallback(handler) without a route parameter (catch-all for any path).

[Fallback]                  // catch-all for any path
public static IResult CatchAll() =>
    Results.Ok();

[Fallback("/{**rest}")]     // catch-all with custom pattern
public static IResult CatchAllWithPattern(string rest) =>
    Results.Ok($"Fallback: {rest}");

Generated:

app.MapFallback(MyNamespace.MyEndpoints.CatchAll);
app.MapFallback("/{**rest}", MyNamespace.MyEndpoints.CatchAllWithPattern);

Produces<sup>[C|M]</sup>

Specifies which status code the endpoint/group will return and for which response type. Can be used multiple times for diferent status codes. The contentType and responseType parameters are optionals.

[Get]
[Produces<User>(200, "application/json")]
//[Produces(200, typeof(User), "application/json")]
//[Produces(200, typeof(User))]
//[Produces(200)]
public static IResult Get() =>
    Results.Ok();

Generated:

ap.MapGet("/", ...)
    .Produces<User>(200, "application/json");
    //.Produces(200, "application/json");
    //.Produces(200);

Cors<sup>[C|M]</sup>

Specifies one or more cors policies that will be applied to endpoint/group. If not specified the default policy will be applied. Can be used multiple times.

[Get]
[Cors]                       // default policy
[Cors("MyCorsPolicy")]       // single policy
[Cors("Policy1", "Policy2")] // multiple policies
public static IResult Get() =>
    Results.Ok();

Generated:

ap.MapGet("/", ...)
    .RequireCors()
    .RequireCors("MyCorsPolicy")
    .RequireCors("Policy1")
    .RequireCors("Policy2");

ExcludeFromDescription<sup>[C|M]</sup>

Hides the endpoint or group from OpenAPI/Swagger documentation.

[Get]
[ExcludeFromDescription]
public static IResult Get() =>
    Results.Ok();

Generated:

ap.MapGet("/", ...)
    .ExcludeFromDescription();

ProducesProblem<sup>[C|M]</sup>

Specifies that the endpoint returns a ProblemDetails response for the given status code. Can be used multiple times for different status codes.

[Get]
[ProducesProblem(400)]
[ProducesProblem<ValidationError>(422)]
[ProducesProblem(500, typeof(ErrorResponse), "application/json")]
public static IResult Get() =>
    Results.Ok();

Generated:

ap.MapGet("/", ...)
    .ProducesProblem(400)
    .ProducesProblem<ValidationError>(422)
    .ProducesProblem<ErrorResponse>(500, "application/json");

Rate Limiting<sup>[C|M]</sup>

Applies rate limiting policies to endpoints or groups.

[EnableRateLimiting("FixedWindow")]  // applies a named policy
[DisableRateLimiting]                // disables rate limiting
public static IResult Get() =>
    Results.Ok();

Generated:

ap.MapGet("/", ...)
    .RequireRateLimiting("FixedWindow");
// or
ap.MapGet("/", ...)
    .DisableRateLimiting();

Note: Rate limiting requires the Microsoft.AspNetCore.RateLimiting package in your project.

Output Caching<sup>[C|M]</sup>

Caches responses for the endpoint or group.

[CacheOutput]                       // default cache profile
[CacheOutput("MyPolicy")]           // named policy
[DisableOutputCache]                // disable caching
public static IResult Get() =>
    Results.Ok();

Generated:

ap.MapGet("/", ...)
    .CacheOutput()
    .CacheOutput("MyPolicy")
    .DisableOutputCache();

Note: Output caching requires the Microsoft.AspNetCore.OutputCaching package in your project.

Request Size Limit<sup>[C|M]</sup>

Limits the request body size for endpoints or groups.

[RequestSizeLimit(30_000_000)]       // 30 MB limit
[DisableRequestSizeLimit]            // no limit
public static IResult Upload() =>
    Results.Ok();

Generated:

ap.MapGet("/", ...)
    .RequireRequestSizeLimit(30000000)
    .DisableRequestSizeLimit();

Endpoint Group Name<sup>[C|M]</sup>

Sets the endpoint group name for OpenAPI/Swagger organization. Unlike [GroupEndpoint], this does not affect routing โ€” it only tags the endpoint with a group name for documentation purposes.

[EndpointGroupName("Users")]
public static IResult Get() =>
    Results.Ok();

Generated:

ap.MapGet("/", ...)
    .WithGroupName("Users");

SkipStatusCodePages<sup>[C|M]</sup>

Skips the status code pages middleware for this endpoint or group. Useful for API endpoints that return error status codes and don't want them intercepted by error pages.

[SkipStatusCodePages]
public static IResult Get() =>
    Results.NotFound();

Generated:

ap.MapGet("/", ...)
    .SkipStatusCodePages();

Request Timeout<sup>[C|M]</sup>

Sets a per-endpoint request timeout. Available in .NET 8+.

[RequestTimeout(5000)]                 // 5 seconds (in milliseconds)
[RequestTimeout("MyPolicy")]           // named timeout policy
[DisableRequestTimeout]                // disable timeout
public static IResult Get() =>
    Results.Ok();

Generated:

ap.MapGet("/", ...)
    .RequireRequestTimeout(TimeSpan.FromMilliseconds(5000))
    .RequireRequestTimeout("MyPolicy")
    .DisableRequestTimeout();

Note: Request timeout requires .NET 8 or higher.

๐Ÿงช Requirements

  • .NET 7 or higher
  • Source generator built with .NET Standard 2.1
  • Roslyn 4.x analyzers included automatically

๐Ÿ› ๏ธ Fixes & Improvements in this version

  • MethodMustBeStaticRule (EZ0003) โ€” Now correctly validates that endpoint methods are static
  • AuthorizationAttribute โ€” Added params string[] constructor for multiple policies: [Authorization("Admin", "SuperUser")]
  • Typos fixed: AddtionalContentTypes โ†’ AdditionalContentTypes, ProducessAttribute.cs โ†’ ProducesAttribute.cs
  • New attributes: [Fallback], [ExcludeFromDescription], [ProducesProblem], [EnableRateLimiting], [DisableRateLimiting], [CacheOutput], [DisableOutputCache], [RequestSizeLimit], [DisableRequestSizeLimit], [EndpointGroupName], [SkipStatusCodePages], [RequestTimeout], [DisableRequestTimeout]
  • CorsAttribute โ€” Added params string[] constructor: [Cors("P1", "P2")]
Product Compatible and additional computed target framework versions.
.NET net5.0 was computed.  net5.0-windows was computed.  net6.0 was computed.  net6.0-android was computed.  net6.0-ios was computed.  net6.0-maccatalyst was computed.  net6.0-macos was computed.  net6.0-tvos was computed.  net6.0-windows was computed.  net7.0 was computed.  net7.0-android was computed.  net7.0-ios was computed.  net7.0-maccatalyst was computed.  net7.0-macos was computed.  net7.0-tvos was computed.  net7.0-windows was computed.  net8.0 was computed.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed.  net9.0 was computed.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 was computed.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
.NET Core netcoreapp3.0 was computed.  netcoreapp3.1 was computed. 
.NET Standard netstandard2.1 is compatible. 
MonoAndroid monoandroid was computed. 
MonoMac monomac was computed. 
MonoTouch monotouch was computed. 
Tizen tizen60 was computed. 
Xamarin.iOS xamarinios was computed. 
Xamarin.Mac xamarinmac was computed. 
Xamarin.TVOS xamarintvos was computed. 
Xamarin.WatchOS xamarinwatchos was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.
  • .NETStandard 2.1

    • No dependencies.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
1.3.0 104 5/16/2026
1.2.0 249 12/19/2025
1.1.0 436 12/11/2025
1.0.0 450 12/9/2025