LinKit.Grpc 2.1.1

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

LinKit.Grpc

NuGet

LinKit.Grpc packages a Roslyn generator and runtime adapters that connect CQRS request types to protobuf-generated gRPC service/client types. You still define and compile .proto contracts with the gRPC tooling; LinKit generates adapters and property mapping for supported shapes.

Install

dotnet add package LinKit.Core
dotnet add package LinKit.Grpc
dotnet add package Grpc.AspNetCore

The application also needs generated C# code for its protobuf contracts, usually produced by Grpc.Tools in the contract/server project. Add the required gRPC tooling package to that project.

Expose a CQRS query as a server RPC

Given a protobuf service:

syntax = "proto3";
option csharp_namespace = "MyApp.Contracts";

service InventoryService {
  rpc CheckStock (CheckStockRequest) returns (CheckStockResponse);
}

message CheckStockRequest {
  string product_code = 1;
  int32 quantity = 2;
}

message CheckStockResponse {
  bool available = 1;
  int32 remaining = 2;
}

Declare the CQRS request and handler:

using LinKit.Core.Cqrs;
using LinKit.Grpc;
using MyApp.Contracts;

[GrpcEndpoint(typeof(InventoryService.InventoryServiceBase), "CheckStock")]
public sealed class CheckStockQuery : IQuery<CheckStockResponse>
{
    public string ProductCode { get; set; } = string.Empty;
    public int Quantity { get; set; }
}

[CqrsHandler]
public sealed class CheckStockHandler : IQueryHandler<CheckStockQuery, CheckStockResponse>
{
    public Task<CheckStockResponse> HandleAsync(
        CheckStockQuery query,
        CancellationToken cancellationToken) =>
        Task.FromResult(new CheckStockResponse
        {
            Available = query.Quantity <= 50,
            Remaining = Math.Max(0, 50 - query.Quantity)
        });
}

Register the gRPC server and map generated services:

builder.Services.AddGrpc();
builder.Services.AddLinKitCqrs();
builder.Services.AddLinKitGrpcServer();

var app = builder.Build();
app.MapLinKitGrpcServices();
app.Run();

The generated service adapter maps the protobuf request into the CQRS request, invokes the mediator, and maps the handler response back to the protobuf response. Validate property names/types and generated source for nested or custom mappings; the generator supports defined property/list mapping patterns, not arbitrary object mapping.

Call a remote RPC through IGrpcMediator

In a client compilation, annotate the CQRS request with the generated protobuf client and RPC method name:

using LinKit.Core.Cqrs;
using LinKit.Grpc;
using MyApp.Contracts;

[GrpcClient(typeof(InventoryService.InventoryServiceClient), "CheckStockAsync")]
public sealed class CheckStockRemoteQuery : IQuery<CheckStockResponse>
{
    public string ProductCode { get; set; } = string.Empty;
    public int Quantity { get; set; }
}

Register the generated mediator and a channel provider. AddLinKitGrpcClient() supplies defaults for interceptor/metadata providers and the client factory; an IGrpcChannelProvider is required:

builder.Services.AddLinKitCqrs();
builder.Services.AddLinKitGrpcClient();
builder.Services.AddGrpcChannel("https://inventory.example.net");

gRPC generated types and registration extensions use the project's <RootNamespace>.Generated namespace. The generator emits a global using for the current assembly; when calling a generated extension from a referenced contracts/service project, import that project's generated namespace explicitly.

Upgrade to 2.0

Generated gRPC adapters and DI extensions now use the consuming assembly's <RootNamespace>.Generated namespace rather than a shared LinKit namespace. The current assembly receives a generated global using; add an explicit using for a referenced assembly's generated namespace when calling its generated registration or mapping APIs.

AddGrpcChannel registers DefaultGrpcChannelProvider, which reuses a channel for each generated gRPC client type. For multiple service addresses, implement the provider:

using System.Collections.Concurrent;
using Grpc.Core;
using Grpc.Net.Client;
using LinKit.Grpc;

public sealed class ServiceChannelProvider(IConfiguration configuration) :
    IGrpcChannelProvider, IDisposable
{
    private readonly ConcurrentDictionary<Type, GrpcChannel> _channels = new();

    public GrpcChannel GetChannelFor<TClient>() where TClient : ClientBase =>
        _channels.GetOrAdd(typeof(TClient), clientType =>
        {
            var address = configuration[$"GrpcClients:{clientType.Name}"]
                ?? throw new InvalidOperationException(
                    $"No gRPC address configured for {clientType.Name}.");
            return GrpcChannel.ForAddress(address);
        });

    public void Dispose()
    {
        foreach (var channel in _channels.Values)
        {
            channel.Dispose();
        }
    }
}
builder.Services.AddGrpcChannelProvider<ServiceChannelProvider>();

Then use the generated remote mediator:

var response = await grpcMediator.QueryAsync(
    new CheckStockRemoteQuery { ProductCode = "SKU-42", Quantity = 3 },
    cancellationToken);

Interceptors and metadata

Providers are per client type and use the actual public interfaces:

public sealed class AppInterceptorProvider : IGrpcInterceptorProvider
{
    public Interceptor[] GetInterceptorsFor<TClient>() => [];
}

public sealed class AppMetadataProvider : IMetadataProvider
{
    public Metadata? GetMetadata() => new Metadata();
}

Register them with the service collection helpers:

builder.Services.AddGrpcInterceptorProvider<AppInterceptorProvider>();
builder.Services.AddGrpcMetadataProvider<AppMetadataProvider>();

Metadata is requested for each outgoing RPC. Do not put untrusted or secret values into logs. Configure authentication/TLS and deadlines using application-specific gRPC options/interceptors.

Runtime and AOT considerations

  • Reuse channels and dispose the provider with the host; do not create a channel per request.
  • Keep client/server protobuf contracts compatible across deployments.
  • Client factory activation uses generated activators when available; a reflection-based activation fallback may remain for unregistered client types.
  • This package's source generation does not certify AOT safety for every gRPC runtime, protobuf type, interceptor, or application configuration. Enable trim/AOT analyzers and publish/run the target application for its RID.

License

MIT. See the repository license.

Product Compatible and additional computed target framework versions.
.NET net8.0 is compatible.  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 is compatible.  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 is compatible.  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. 
Compatible target framework(s)
Included target framework(s) (in 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
2.1.1 98 10/31/2026
2.1.0 97 10/30/2026
2.0.0 101 10/24/2026
1.2.0 93 10/22/2026
1.1.0 99 10/20/2026
1.0.5 850 10/6/2025
1.0.4 750 9/27/2025
1.0.3 781 9/26/2025
1.0.2 801 9/26/2025
1.0.1 803 9/26/2025
1.0.0 798 9/5/2025