SimpleKafkaLibrary 2.1.1

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

SimpleKafkaLibrary 2.1.1

Lightweight Kafka helper for .NET 8 (Confluent.Kafka). Public API matches 2.0 (ConsumeAsync, ConsumeRequestAsync, IMessageProducers, AddKafkaServices) so existing callers keep working.

What’s lighter in 2.1.x

Area 2.0 behavior 2.1.x behavior
Produce New IProducer on every call One shared producer per process (null-key + string-key)
ConsumeAsync One librdkafka client per topic One shared consumer for all topics on that ConsumerBase
ConsumeRequestAsync One client per topic + new producer per reply One shared request-reply consumer + reused reply producer
Producer queue Up to ~1 GB cap Soft cap ~16 MB
Consumer fetch buffers Large defaults Soft caps (~4 MB queue, 1 MB fetch)
Request-reply poll Every 100 ms Default 250 ms (configurable)
DI startup BuildServiceProvider() + start during registration IHostedService after the host starts
Broker down Topic ensure / consume could crash the host Log + retry; host keeps running
Subscribe logs Information Debug

ProduceAsync returns false when the broker is unreachable (within ProduceAsyncTimeoutMs). Callers (WCL/CCL) can fall through to SignalR/gRPC.

Package

<PackageReference Include="SimpleKafkaLibrary" Version="2.1.1" />

Configuration

Bind under a section such as "Kafka". KafkaConfig inherits Confluent ProducerConfig, so standard keys like BootstrapServers work in the same section.

"Kafka": {
  "BootstrapServers": "localhost:9092",
  "UseKafka": true,
  "UseEncryptedData": false,
  "EncryptedKey": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
  "FlushProducerInSeconds": 2,
  "ConsumedInSeconds": 2,
  "RequestReplyMinTimeoutMs": 100,
  "RequestReplyMaxTimeoutMs": 2000,
  "RequestReplyConsumedInMilliseconds": 250,
  "ProduceAsyncTimeoutMs": 1000,
  "ProducerRetryCount": 5,
  "ProducerRetryBackoffMs": 200,
  "MaxPollIntervalMs": 300000,
  "ConsumerQueuedMaxMessagesKbytes": 4096,
  "ConsumerFetchMaxBytes": 1048576,
  "ConsumerMaxPartitionFetchBytes": 1048576
}
Setting Default Notes
UseKafka false When false, produce/consume are no-ops
ConsumedInSeconds 2 Async consumer poll interval
RequestReplyConsumedInMilliseconds 250 Request-reply poll interval (lower = more CPU)
ProduceAsyncTimeoutMs 1000 ProduceAsync returns false if broker does not accept in time
ConsumerQueuedMaxMessagesKbytes 4096 Soft cap for each consumer’s local fetch queue
ConsumerFetchMaxBytes 1048576 Max bytes per fetch
ConsumerMaxPartitionFetchBytes 1048576 Max bytes per partition fetch

EncryptedKey is required only when UseEncryptedData is true. Prefer secrets from configuration / a secret store — do not ship production keys in source.

DI registration

Producer only (host starts its own consumers)

services.AddKafkaServices(configuration.GetSection("Kafka"));

One consumer type (started as IHostedService)

services.AddKafkaServices<Consumer>(configuration.GetSection("Kafka"));

Multiple consumers

services.AddKafkaServices(cfg =>
{
    cfg.Configure(configuration.GetSection("Kafka"));
    cfg.RegisterConsumer<Consumer>();
    cfg.RegisterConsumer<UserConsumer>();
});

Or scan an assembly:

services.AddKafkaServices(cfg =>
{
    cfg.Configure(configuration.GetSection("Kafka"));
    cfg.RegisterConsumer(Assembly.GetExecutingAssembly());
});

Consumers start when the host starts (not during service registration). Broker outages are retried every few seconds and do not stop the process.

Producer usage

public class CreateUserCommandHandler
{
    private readonly IMessageProducers _messageProducers;

    public CreateUserCommandHandler(IMessageProducers messageProducers)
    {
        _messageProducers = messageProducers;
    }

    public async Task Handle(CancellationToken cancellationToken)
    {
        // Fire-and-forget (still uses the shared durable producer)
        await _messageProducers.WriteFireAndForget("User", newUser).ConfigureAwait(false);

        // true = broker accepted; false = Kafka disabled, down, or timed out
        var published = await _messageProducers.ProduceAsync("User", newUser).ConfigureAwait(false);

        // Optional partition key
        await _messageProducers.ProduceWithKeyAsync("User", userId.ToString("N"), newUser)
            .ConfigureAwait(false);
    }
}

Request-reply producer

Pair with ConsumeRequestAsync on the consumer. Wait time is clamped between RequestReplyMinTimeoutMs and RequestReplyMaxTimeoutMs.

var result = await _messageProducers.ProduceWaitForFResponseAsync<CreateUserRequest, CreateUserFeedback>(
    "User",
    request,
    cancellationToken: cancellationToken).ConfigureAwait(false);

if (result.IsSuccessful)
{
    var feedback = result.Data;
}

var fastResult = await _messageProducers.ProduceWaitForFResponseAsync<CreateUserRequest, CreateUserFeedback>(
    "User",
    request,
    responseTimeoutMs: 500,
    cancellationToken: cancellationToken).ConfigureAwait(false);

When Kafka is down, request-reply returns IsSuccessful = false (transaction rolled back). It does not crash the host.

Consumer usage

ConsumerBase requires ILoggerFactory (2.0+). Multiple ConsumeAsync / ConsumeRequestAsync calls on the same instance share one underlying Kafka client per mode.

public class Consumer : ConsumerBase
{
    public Consumer(
        KafkaConfig configuration,
        IMessageAdmin messageAdmin,
        ILoggerFactory loggerFactory)
        : base("my-service-group", configuration, messageAdmin, loggerFactory)
    {
    }

    public override async Task Invoke()
    {
        var task1 = ConsumeAsync<string>("testTopic", value =>
        {
            Console.WriteLine(value);
        });

        var task2 = ConsumeAsync<MyEvent>("testTopic2", evt =>
        {
            // handle evt
        });

        await Task.WhenAll(task1, task2);
        await base.Invoke();
    }
}

Offsets are committed only after the handler succeeds.

Request-reply consumer

public class UserConsumer : ConsumerBase
{
    public UserConsumer(
        KafkaConfig configuration,
        IMessageAdmin messageAdmin,
        ILoggerFactory loggerFactory)
        : base("user-group", configuration, messageAdmin, loggerFactory)
    {
    }

    public override async Task Invoke()
    {
        await ConsumeRequestAsync<CreateUserRequest, CreateUserFeedback>("User", request =>
        {
            if (string.IsNullOrWhiteSpace(request.Email))
            {
                return new CreateUserFeedback
                {
                    Success = false,
                    Message = "Email is required."
                };
            }

            return new CreateUserFeedback
            {
                Success = true,
                Message = "User created successfully.",
                UserId = Guid.NewGuid()
            };
        });

        await base.Invoke();
    }
}

Reply topic is {topic}-reply (created automatically when the broker is available).

Broker-down behavior (UseKafka: true)

Operation Result
Topic create / exists Warning logged; host continues
Consume loop Reconnect / retry (~5s)
Hosted consumer fault Caught and retried; host keeps running
ProduceAsync Returns false
WriteFireAndForget Best-effort; does not stop the host
ProduceWaitForFResponseAsync IsSuccessful = false

Set UseKafka: false to skip all Kafka I/O without changing call sites.

Notes

  • Use a distinct consumer groupId per service so each host gets its own copy of topic traffic.
  • Prefer gRPC for sync RPC when available; Kafka request-reply is heavier (per-call reply consumer + transactional produce).
  • You can still create multiple ConsumerBase subclasses; each instance gets its own shared async consumer and shared request-reply consumer.

License

This project is licensed with the MIT 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 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. 
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 103 8/13/2026
2.0.0 224 6/22/2026
1.0.7 987 5/15/2025
1.0.6 1,097 2/25/2025
1.0.5 338 1/20/2025
1.0.4 209 12/27/2024
1.0.3 193 12/17/2024
1.0.2 1,899 11/27/2024
1.0.1 215 6/22/2024
1.0.0 205 6/22/2024