Kanject.Core.Api.Annotations 1.8.0

Prefix Reserved
dotnet add package Kanject.Core.Api.Annotations --version 1.8.0
                    
NuGet\Install-Package Kanject.Core.Api.Annotations -Version 1.8.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="Kanject.Core.Api.Annotations" Version="1.8.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Kanject.Core.Api.Annotations" Version="1.8.0" />
                    
Directory.Packages.props
<PackageReference Include="Kanject.Core.Api.Annotations" />
                    
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 Kanject.Core.Api.Annotations --version 1.8.0
                    
#r "nuget: Kanject.Core.Api.Annotations, 1.8.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 Kanject.Core.Api.Annotations@1.8.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=Kanject.Core.Api.Annotations&version=1.8.0
                    
Install as a Cake Addin
#tool nuget:?package=Kanject.Core.Api.Annotations&version=1.8.0
                    
Install as a Cake Tool

Kanject.Core.Api.Annotations

Kanject.Core.Api.Annotations is a Roslyn source generator plus analyzers for ASP.NET Core minimal APIs. You write endpoints as public static methods on a static class marked [ApiEndpoints]; at compile time it generates the MapGroup / MapGet / MapPost … registration code, carries your XML doc comments into OpenAPI summaries and descriptions, and writes a Markdown catalog of every route on each build.

Analyzers catch the mistakes that would otherwise make the generator skip an endpoint without telling you — a non-static class, a private method, duplicate routes — and four of them come with code fixes.

Installation

dotnet add package Kanject.Core.Api.Abstractions
dotnet add package Kanject.Core.Api.Annotations
<ItemGroup>
  <PackageReference Include="Kanject.Core.Api.Abstractions" />                   
  <PackageReference Include="Kanject.Core.Api.Annotations" PrivateAssets="all" /> 
</ItemGroup>

This package is not marked as a development dependency, so dotnet add package writes a plain reference without PrivateAssets or IncludeAssets. Add PrivateAssets="all" yourself so the generator and its build targets stay in your project instead of flowing to projects that reference it.

The attribute types live in Kanject.Core.Api.Abstractions (there is no separate .Attributes package). Kanject.Core.Api and Kanject.Core.ApiV2 both bring that package in, but neither references this generator — add it explicitly wherever you declare [ApiEndpoints] classes. It depends on Kanject.Core.Annotations, which NuGet restores automatically.

The analyzer assembly targets netstandard2.0. Use it in ASP.NET Core projects on .NET 8, .NET 9 or .NET 10: the attribute types come from Kanject.Core.Api.Abstractions (net8.0–net10.0), and the generated code uses minimal-API route groups.

Quick start

using Kanject.Core.Api.Abstractions.Attributes;
using Microsoft.AspNetCore.Authorization;

namespace Contoso.Orders.Endpoints;

/// <summary>Order management endpoints.</summary>
[ApiEndpoints("Orders", "api/orders")]
public static class OrderEndpoints
{
    /// <summary>Lists the caller's orders.</summary>
    [HttpGet]
    public static async Task<IResult> ListOrders(IOrderStore store, CancellationToken ct)
        => Results.Ok(await store.ListAsync(ct));

    /// <summary>Returns one order.</summary>
    /// <remarks>Responds 404 when the order does not exist.</remarks>
    [HttpGet("{id:guid}")]
    public static async Task<IResult> GetOrder(Guid id, IOrderStore store, CancellationToken ct)
        => await store.FindAsync(id, ct) is { } order ? Results.Ok(order) : Results.NotFound();

    /// <summary>Liveness probe for the orders group.</summary>
    [AllowAnonymous]
    [HttpGet("ping")]
    public static IResult PingOrders() => Results.Ok();
}
using Contoso.Orders.Endpoints;

var builder = WebApplication.CreateBuilder(args);
builder.Services.AddAuthentication(/* your scheme */);
builder.Services.AddAuthorization();
builder.Services.AddScoped<IOrderStore, OrderStore>();

var app = builder.Build();
app.UseAuthentication();
app.UseAuthorization();

app.MapKanjectEndpoints();   // every [ApiEndpoints] class in this project

app.Run();

Enable XML documentation in the project so the compiler parses your doc comments — the generator reads <summary> and <remarks> from them, and without it KANAPI011 reports every endpoint as undocumented:

<PropertyGroup>
  <GenerateDocumentationFile>true</GenerateDocumentationFile>
</PropertyGroup>

What gets generated

For each [ApiEndpoints] class, in the class's namespace (abridged):

public sealed class OrderEndpointsEndpointOptions
{
    public Action<RouteHandlerBuilder>? ListOrders { get; set; }
    public Action<RouteHandlerBuilder>? GetOrder { get; set; }
    public Action<RouteHandlerBuilder>? PingOrders { get; set; }
}

public static class OrderEndpointsRouteRegistration
{
    public static IEndpointRouteBuilder MapOrderEndpoints(this IEndpointRouteBuilder app,
        Action<RouteGroupBuilder>? configureGroup = null,
        Action<OrderEndpointsEndpointOptions>? configureEndpoints = null)
    {
        var group = app.MapGroup("api/orders")
            .WithTags("Orders")
            .RequireAuthorization()
            .WithDescription("Order management endpoints.");
        configureGroup?.Invoke(group);
        // ...
        var endpointGetOrder = group.MapGet("{id:guid}", OrderEndpoints.GetOrder)
            .WithName(nameof(OrderEndpoints.GetOrder))
            .WithSummary("Returns one order.")
            .WithDescription("Responds 404 when the order does not exist.");
        endpointOptions.GetOrder?.Invoke(endpointGetOrder);
        // ...
        return app;
    }
}

Plus one KanjectEndpointRegistration.MapKanjectEndpoints() that calls every group's Map{ClassName}(). It is generated into the shortest namespace among your endpoint classes, so import that namespace where you call it.

Groups, routes and authorization

[ApiEndpoints] takes the OpenAPI tag and the route prefix positionally, or as named properties:

Property Default Effect
EndpointGroupName The class name WithTags(...) on the group
Route "" Prefix passed to MapGroup(...)
RequireAuthorization true RequireAuthorization() on the group — register authentication and authorization, or set this to false
AuthPolicy none Group-wide policy, RequireAuthorization("<policy>") — applied only while RequireAuthorization is true

Verb attributes take an optional route template relative to the group ([HttpGet("{id:guid}")]); no template maps the group root. Per method, use ASP.NET Core's own attributes from Microsoft.AspNetCore.Authorization: [AllowAnonymous] opts the endpoint out of the group requirement, and [Authorize(Policy = "...")] or [Authorize(Roles = "...")] adds a requirement. The generator mirrors them as AllowAnonymous() / RequireAuthorization(...) calls on the endpoint.

Configuring groups and endpoints

Call the per-group method instead of MapKanjectEndpoints() when a group needs extra conventions:

app.MapOrderEndpoints(
    configureGroup: group => group.RequireCors("frontend"),
    configureEndpoints: endpoints =>
    {
        endpoints.PingOrders = endpoint => endpoint.ExcludeFromDescription();
    });

MapKanjectEndpoints() maps every group with no callbacks. Don't call it and a per-group Map…() for the same class, or the routes are registered twice.

Rules and gotchas

  • The class must be static (KANAPI001) and endpoint methods public static (KANAPI002); anything else is skipped by the generator.
  • Each endpoint is named after its method (WithName(nameof(...))). ASP.NET Core requires endpoint names to be unique, and OpenAPI tools use them as operation IDs, so keep method names unique across all [ApiEndpoints] classes — ListOrders, not List.
  • Only the first verb attribute on a method is used (KANAPI013).
  • Return IResult or a concrete type; MVC's IActionResult belongs to controllers (KANAPI007), and void / Task give an implicit empty 200 (KANAPI008).
  • The Kanject verb attributes share their names with Microsoft.AspNetCore.Mvc.HttpGetAttribute and friends. If an endpoint file also imports Microsoft.AspNetCore.Mvc (for [FromBody], [FromServices], …), [HttpGet] becomes ambiguous — alias or fully qualify one of them.

API schema document

After each build the package's MSBuild targets write <AssemblyName>.apischema.md next to the project file: a Markdown catalog with an overview, endpoint groups, a route map, an authorization matrix, OpenAPI documentation coverage and registration snippets. It is useful as reference documentation and as context for AI coding assistants.

MSBuild property Default Effect
GenerateApiSchema true Set false to skip writing the file
ApiSchemaOutputDir Project directory Relative (to the project) or absolute output directory

To extract the document, the targets set EmitCompilerGeneratedFiles to true when GenerateApiSchema is on and you haven't set it yourself, so generated sources are also written under obj/. The generator additionally embeds the same Markdown in your compiled assembly as [assembly: AssemblyMetadata("ApiSchema", ...)]; GenerateApiSchema=false does not remove that attribute.

Diagnostics

ID Severity What it means
KANAPI001 Error [ApiEndpoints] class is not static, so the generator skips it (code fix: make static).
KANAPI002 Error A method with a verb attribute is not public static, so it is skipped (code fix: make public static).
KANAPI003 Warning A Kanject verb attribute is on a method whose class lacks [ApiEndpoints] and has no effect (code fix: add [ApiEndpoints]).
KANAPI004 Warning [ApiEndpoints] class contains no verb-annotated methods.
KANAPI005 Error Two methods in a group map the same verb and route template — a runtime route conflict.
KANAPI007 Info Endpoint returns MVC IActionResult / ActionResult; return IResult or a concrete type.
KANAPI008 Warning Endpoint returns void or bare Task; return an IResult for an explicit status code.
KANAPI009 Info [AllowAnonymous] is redundant because the group sets RequireAuthorization = false.
KANAPI010 Info [Authorize] without a policy or roles is redundant because the group already requires authorization.
KANAPI011 Info Endpoint method has no XML <summary>, so its OpenAPI summary will be empty.
KANAPI012 Warning Route template starts with /, which can produce // after the group prefix (code fix: remove it).
KANAPI013 Warning Method has more than one verb attribute; only the first is used.
KANJECTAPISCHEMA001 Warning Generating the API schema document failed; route registrations are still generated.
Package Role Availability
Kanject.Core.Api.Abstractions The [ApiEndpoints] and verb attribute types, plus response envelope helpers for minimal APIs nuget.org
Kanject.Core.Api Controllers, exception middleware (Kanject envelope errors) and tenant middleware nuget.org
Kanject.Core.ApiV2 Controllers, exception middleware (Problem Details errors) and tenant middleware nuget.org
Kanject.Core.Annotations Shared Kanject source-generator infrastructure (dependency of this package) nuget.org

License

Licensed under the Kanject Code Libraries License Agreement (KCLLA); the full text ships in this package as LICENSE.md. Organizations whose trailing-twelve-month gross revenue and total funding raised are each below US$250,000 may use it at no cost under the Free Tier. At or above either threshold a commercial license is required — contact commercial@kanjectbusiness.com.

There are no supported framework assets in this package.

Learn more about Target Frameworks and .NET Standard.

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.8.0 45 10/5/2026
1.7.1 51 10/5/2026
1.7.0 57 10/2/2026
1.6.1 110 9/27/2026
1.6.0 93 9/27/2026
1.5.7 92 9/26/2026
1.5.6 134 9/7/2026
1.5.5 106 8/27/2026
1.5.4 104 8/22/2026
1.5.3 114 8/10/2026
1.5.2 111 8/9/2026
1.5.1 128 8/5/2026
1.5.0 119 8/5/2026
1.4.0 124 8/3/2026
1.3.5 125 7/30/2026
1.3.4 124 7/18/2026
1.3.3 154 7/13/2026
1.3.2 123 7/11/2026
1.3.1 125 7/11/2026
1.3.0 125 7/9/2026
Loading failed