Kanject.Core.Channels.Annotations 3.14.0

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

Kanject.Core.Channels.Annotations

Roslyn source generator, analyzer, and code fix for Kanject channels. Annotate a batch handler with [Channel] and this package generates, at compile time, a typed writer interface, a DI registration extension, and either a hosted BackgroundService consumer or an AWS Lambda invocation-local drain helper — all running on the Kanject.Core.Channels engine. The analyzer reports handler-shape and configuration mistakes as build diagnostics (KANCHN…).

Installation

<ItemGroup>
  <PackageReference Include="Kanject.Core.Channels" />                                   
  <PackageReference Include="Kanject.Core.Channels.Annotations" PrivateAssets="all" />   
</ItemGroup>

dotnet add package Kanject.Core.Channels.Annotations writes an IncludeAssets line for this package that omits compile. Delete that line (keep PrivateAssets="all") — otherwise the attribute types from Kanject.Core.Channels.Annotations.Attributes can be stripped from compilation.

This is a development-only package (DevelopmentDependency): it ships the generator under analyzers/ and adds no runtime assembly to your output. Kanject.Core.Channels does not reference it, so add it explicitly to every project that declares [Channel] handlers. The runtime does reference Kanject.Core.Channels.Annotations.Attributes, which supplies the attribute types.

The generator targets netstandard2.0 and runs inside the compiler. The code it emits uses Kanject.Core.Channels, which targets .NET 8, .NET 9 and .NET 10.

Quick start

using Kanject.Core.Channels.Annotations.Attributes;

namespace Shop.Orders;

public sealed record OrderPlaced(string OrderId, decimal Total);

public sealed partial class OrderProjector(IOrderReadModel readModel)
{
    [Channel(Capacity = 5000, BatchSize = 25, FlushIntervalMs = 200)]
    public async ValueTask ProjectAsync(ReadOnlyMemory<OrderPlaced> batch, CancellationToken ct)
    {
        await readModel.UpsertAsync(batch.ToArray(), ct);
    }
}
// Composition root
builder.Services.AddOrderProjectorProjectAsyncChannel();

// Producer
public sealed class CheckoutService(IOrderProjectorProjectAsyncChannelWriter orders)
{
    public ValueTask OnOrderPlacedAsync(OrderPlaced order, CancellationToken ct) =>
        orders.WriteAsync(order, ct);
}

The handler is an ordinary method with a body; only its containing type must be partial. The generated files fully qualify every type and DI extension call, so they compile without any using in your project — including a plain Microsoft.NET.Sdk project with ImplicitUsings off.

What gets generated

For a [Channel] method M on type T with item type TItem (hint names are T_M.*.g.cs):

Output Generated code When
ChannelWriter.g.cs public interface IT{M}ChannelWriter : IChannelWriter<TItem> — WriteAsync(item), WriteAsync(ReadOnlyMemory<TItem>), WriteAllAsync(IAsyncEnumerable<TItem>), TryWrite, CompleteAsync, ChannelName. Emitted internal when TItem is not public. Always
DiExtension.g.cs AddT{M}Channel(this IServiceCollection services, Action<ChannelOptions>? configure = null) and const string ServiceKey in T{M}ChannelServiceCollectionExtensions, plus an internal in-process writer Always
HostedService.g.cs internal sealed class T{M}ChannelService : ChannelHostedServiceBase<TItem> Resolved mode InProcess
InvocationDrainer.g.cs public static class T{M}ChannelDrain with DrainAsync(IServiceProvider serviceProvider, TimeSpan remainingTime, CancellationToken cancellationToken = default) Resolved mode InvocationLocal

Everything is emitted into the handler's namespace. ChannelName defaults to T_M and can be overridden with [Channel(ChannelName = "…")]; it does not change the generated type names.

The DI extension copies the attribute values into a ChannelOptions (Capacity, FullMode, BatchSize, FlushInterval, RestartOnFault, MaxRestartAttempts, SafetyMargin), runs your configure callback, and creates the bounded channel. FullMode is mapped to the BoundedChannelFullMode member of the same name. The extension then registers:

  • ChannelOptions, Channel<TItem>, ChannelReader<TItem> and ChannelWriter<TItem> as keyed singletons under T{M}ChannelServiceCollectionExtensions.ServiceKey (the handler's fully qualified Namespace.Type.Method). Several channels — including several over the same item type — therefore coexist in one container. Resolve them with GetRequiredKeyedService<ChannelWriter<TItem>>(T{M}ChannelServiceCollectionExtensions.ServiceKey) or [FromKeyedServices(…)]. Nothing is registered unkeyed.
  • The writer interface IT{M}ChannelWriter as a singleton bound to this channel.
  • In InProcess mode, the hosted consumer (built over this channel's reader and options) and the handler type with the lifetime from Lifetime (Scoped by default, which gives each batch its own async DI scope).

Calling the same AddT{M}Channel twice on one IServiceCollection throws InvalidOperationException: the host de-duplicates the hosted consumer by type, so a second registration would leave a writer feeding a channel nobody drains.

Mode resolution

ChannelMode.Default is resolved when the project compiles: InvocationLocal if the compilation references Kanject.Core.CloudFunction.Provider.AwsLambda, otherwise InProcess. Distributed emits only the writer interface and the DI extension — no consumer.

Handler shape the generator expects

  • An ordinary method (not a local function, lambda, operator, accessor or explicit interface implementation — KANCHN024), non-generic and on a non-generic type (KANCHN019).
  • public, internal or protected internal, on containing types that are too (KANCHN022): the generated consumer is a separate type that calls it.
  • Returns Task or ValueTask (KANCHN003; async void included).
  • The partition is the first parameter that isn't a CancellationToken: TItem for per-item handlers, or ReadOnlyMemory<TItem> / IReadOnlyList<TItem> for batched ones (KANCHN004). ReadOnlyMemory<TItem> is passed through without copying; an IReadOnlyList<TItem> handler receives a copy of each batch as an array, in every mode. TItem can't be a ref struct or pointer (KANCHN023).
  • A CancellationToken is optional and may appear in any position; the consumer forwards its token to the first one.
  • Generated consumers bind arguments by name, so any other parameter must be optional or params and keeps its default (KANCHN021). No parameter may be ref, out, in or ref readonly (KANCHN020).

The generator emits nothing for a method that breaks any of these rules; the analyzer reports why.

Things the generated wiring does not do

  • In InvocationLocal mode the DI extension does not register the handler type — register it yourself.
  • [ChannelProducer] generates nothing; every use is reported as KANCHN017. Use a [Channel(Mode = ChannelMode.Distributed)] handler for a producer-only port.

See the Kanject.Core.Channels package for the drain contracts, the Lambda guidance, and ChannelOptions.

Diagnostics

ID Severity What it means
KANCHN002 Error The type containing an instance [Channel] method is not partial. Code fix: "Make containing type partial".
KANCHN003 Error The method does not return Task or ValueTask.
KANCHN004 Error No item/batch parameter (T, ReadOnlyMemory<T>, IReadOnlyList<T>) besides the CancellationToken.
KANCHN005 Error BatchSize > 1 but the parameter is a single item.
KANCHN006 Warning Batch-shaped parameter with BatchSize = 1; every batch holds one item.
KANCHN007 Error Capacity is not > 0.
KANCHN010 Warning Mode = InvocationLocal but the project does not reference Kanject.Core.CloudFunction.Provider.AwsLambda.
KANCHN011 Error [Channel] and [Parallel] on the same method.
KANCHN013 Warning FullMode = DropOldest, DropWrite or DropNewest drops items silently on overflow.
KANCHN014 Error MaxRestartAttempts = 0; use -1, a positive value, or RestartOnFault = false.
KANCHN015 Warning [Channel] on a static method; no DI resolution, the method is called directly.
KANCHN017 Error [ChannelProducer] is not supported; no code is generated for it.
KANCHN018 Error FullMode is not a defined ChannelFullMode member (e.g. (ChannelFullMode)42); no wiring is generated for the method.
KANCHN019 Error The method is generic, or is declared on a generic type; no wiring is generated.
KANCHN020 Error A parameter is ref, out, in or ref readonly; the consumer passes arguments by value.
KANCHN021 Error A required parameter other than the item/batch and the first CancellationToken; the consumer can't supply it. Make it optional.
KANCHN022 Error The method, or a type containing it, is private, protected, private protected or file-local; the generated consumer can't call it.
KANCHN023 Error The item type is a ref struct or pointer and can't be a Channel<T> element.
KANCHN024 Error [Channel] is on a local function, lambda, operator, accessor or explicit interface implementation; only ordinary methods are supported.

If the generator itself throws while emitting code, it reports KANJECTGEN001 (Error) with the exception message instead of failing silently.

Package Role Availability
Kanject.Core.Channels Runtime engine the generated code calls nuget.org
Kanject.Core.Channels.Annotations.Attributes [Channel], [ChannelProducer], ChannelMode, ChannelFullMode, ChannelLifetime nuget.org
Kanject.Core.CloudFunction.Provider.AwsLambda Lambda hosting; its reference selects InvocationLocal for ChannelMode.Default nuget.org
Kanject.Core.Channels.Provider.AwsSqs.Annotations Generator for [SqsChannel] SQS Lambda entry points Commercial license (not on nuget.org)
Kanject.Core.Channels.Provider.AwsKinesis.Annotations Generator for [KinesisChannel] Kinesis Lambda entry points Commercial license (not on 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
3.14.0 45 10/5/2026
3.13.1 126 9/27/2026
3.13.0 85 9/27/2026
3.12.7 94 9/26/2026
3.12.6 118 9/7/2026
3.12.5 100 8/27/2026
3.12.4 107 8/22/2026
3.12.3 132 8/10/2026
3.12.2 112 8/9/2026
3.12.1 122 8/5/2026
3.12.0 127 8/5/2026
3.11.0 121 8/3/2026
3.10.5 123 7/30/2026
3.10.4 131 7/18/2026
3.10.3 133 7/13/2026
3.10.2 122 7/11/2026
3.10.1 126 7/11/2026
3.10.0 120 7/9/2026
3.9.1 123 7/9/2026