KubeMQ
Integrations.NET AspireTutorials

Getting Started with .NET Aspire

Provision KubeMQ in an Aspire AppHost and send your first message from a service project in minutes.

The KubeMQ .NET Aspire integration ships two NuGet packages that follow the standard Aspire two-package model: KubeMQ.Aspire.Hosting provisions a KubeMQ container as a resource in your AppHost, and KubeMQ.Aspire.Client wires an IKubeMQClient into a service project with health checks, OpenTelemetry, and keyed dependency injection. This guide takes you from an empty Aspire solution to publishing your first event and queue message.

Setup walkthrough

Prerequisites

You need the following installed before you begin:

RequirementVersion
.NET SDK8.0 or 9.0
.NET Aspire workload9.0+
DockerRunning (for local container provisioning)
KubeMQ license keySet via WithLicenseKey()

Aspire provisions the KubeMQ broker as a local Docker container, so Docker must be running. The license key is supplied at deploy time as a secret parameter — you will add it in the AppHost step.

Install the Packages

Add the hosting package to your AppHost project:

dotnet add package KubeMQ.Aspire.Hosting

Add the client package to each service project that talks to KubeMQ:

dotnet add package KubeMQ.Aspire.Client

These packages build on Aspire.Hosting 9.0.0 and the KubeMQ.SDK.CSharp 3.0.1 client. If your solution uses central package management (Directory.Packages.props), pin those versions there.

Configure the AppHost

In the AppHost Program.cs, declare the license key as a secret parameter, provision the broker, and reference it from your service project. The WaitFor call ensures the service does not start until the broker is healthy.

AppHost/Program.cs
var builder = DistributedApplication.CreateBuilder(args);

var kubemqKey = builder.AddParameter("kubemq-key", secret: true);

var messaging = builder.AddKubeMQ("messaging")
    .WithLicenseKey(kubemqKey)
    .WithDataVolume();

builder.AddProject<Projects.KubeMQ_Aspire_Sample_WebApi>("webapi")
    .WithReference(messaging)
    .WaitFor(messaging);

builder.Build().Run();

AddKubeMQ("messaging") names the resource messaging — remember this name, because the service project uses it to resolve the connection. WithLicenseKey sets the KUBEMQ_TOKEN environment variable on the container from the secret parameter, and WithDataVolume binds a persistent volume to /store so messages survive container restarts.

The kubemq-key parameter value is read from configuration. For local development, set it once with dotnet user-secrets set Parameters:kubemq-key <your-license-key> in the AppHost project, or add it to appsettings.json under the Parameters section.

What AddKubeMQ Does

Behind the scenes, AddKubeMQ registers a container resource and configures it for you:

  • Pulls the europe-docker.pkg.dev/kubemq/images/kubemq:2.5.0 image.
  • Exposes three endpoints — gRPC on target port 50000, REST on 9090, and the Dashboard on 8080.
  • Uses a persistent container lifetime (ContainerLifetime.Persistent), so the container — and the data volume bound at /store — survives AppHost restarts.

This means the broker keeps running between debug sessions and your queued messages are not lost when you stop and restart the AppHost.

Configure the Service Project

In your service project Program.cs, register the KubeMQ client. The connection name passed to AddKubeMQClient must match the resource name from the AppHost (messaging). Aspire injects the host:port connection string automatically — you never hardcode an address.

WebApi/Program.cs
var builder = WebApplication.CreateBuilder(args);
builder.AddKubeMQClient("messaging");
builder.Services.AddControllers();

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

AddKubeMQClient registers an IKubeMQClient singleton, binds settings from the Aspire:KubeMQ:Client configuration section, and enables health checks (tagged ready and live), OpenTelemetry tracing (AddSource("KubeMQ.Sdk")), and metrics (AddMeter("KubeMQ.Sdk")) by default.

For multiple KubeMQ instances in one service, use AddKeyedKubeMQClient("name") for each connection and resolve them with [FromKeyedServices("name")]. See the Multiple KubeMQ Instances guide for details.

Send Your First Message

Inject IKubeMQClient into a controller and publish an event. Events are fire-and-forget — no response is expected. This controller builds an EventMessage on the events.example channel and calls SendEventAsync.

WebApi/Controllers/EventsController.cs
using System.Text;
using KubeMQ.Sdk.Client;
using KubeMQ.Sdk.Events;
using Microsoft.AspNetCore.Mvc;

namespace KubeMQ.Aspire.Sample.WebApi.Controllers;

[ApiController]
[Route("api/[controller]")]
public sealed class EventsController : ControllerBase
{
    private readonly IKubeMQClient _client;

    public EventsController(IKubeMQClient client) => _client = client;

    [HttpPost]
    public async Task<IActionResult> PublishEvent([FromBody] string body)
    {
        var message = new EventMessage
        {
            Channel = "events.example",
            Body = Encoding.UTF8.GetBytes(body),
            Tags = new Dictionary<string, string> { ["source"] = "aspire-sample" },
        };

        await _client.SendEventAsync(message);
        return Ok(new { Status = "published" });
    }
}

POST a JSON string body to /api/events and the message is published to the events.example channel.

Try a Queue (Send and Receive)

Events are one pattern; queues are another. Queue messages are persisted and consumed at-least-once, which makes them a good fit for work distribution. The same IKubeMQClient sends with SendQueueMessageAsync and pulls with ReceiveQueueMessagesAsync. The poll request below requests up to 5 messages, waits up to 5 seconds, and auto-acknowledges on receipt.

WebApi/Controllers/QueuesController.cs
using System.Text;
using KubeMQ.Sdk.Client;
using KubeMQ.Sdk.Queues;
using Microsoft.AspNetCore.Mvc;

namespace KubeMQ.Aspire.Sample.WebApi.Controllers;

[ApiController]
[Route("api/[controller]")]
public sealed class QueuesController : ControllerBase
{
    private readonly IKubeMQClient _client;

    public QueuesController(IKubeMQClient client) => _client = client;

    [HttpPost]
    public async Task<IActionResult> SendMessage([FromBody] string body)
    {
        var message = new QueueMessage
        {
            Channel = "queues.example",
            Body = Encoding.UTF8.GetBytes(body),
        };

        var result = await _client.SendQueueMessageAsync(message);
        return Ok(new { result.MessageId, result.IsError, result.Error });
    }

    [HttpGet]
    public async Task<IActionResult> ReceiveMessages()
    {
        var request = new QueuePollRequest
        {
            Channel = "queues.example",
            MaxMessages = 5,
            WaitTimeoutSeconds = 5,
            AutoAck = true,
        };

        var response = await _client.ReceiveQueueMessagesAsync(request);
        var messages = response.Messages.Select(m => new
        {
            m.MessageId,
            Body = Encoding.UTF8.GetString(m.Body.Span),
        }).ToList();

        return Ok(new { Count = messages.Count, Messages = messages });
    }
}

POST to /api/queues to enqueue a message, then GET /api/queues to drain up to five messages from the queues.example queue.

Run It

Start the whole distributed application from the AppHost project:

dotnet run

Aspire launches the dashboard in your browser. There you can confirm that the messaging container and the webapi resource are running and healthy. The sample service project calls MapDefaultEndpoints in its ServiceDefaults, which maps two health endpoints:

EndpointReports
/healthChecks tagged ready (the broker connection is ready)
/aliveChecks tagged live (the process is live)

A green health indicator on webapi means the KubeMQ readiness check passed and the client is connected to the broker.

Worker-Style Services

Not every service is a web app. In a background worker or console service, use Host.CreateApplicationBuilder(args) instead of WebApplication.CreateBuilder(args). The client registration is identical — resolve IKubeMQClient from the host and call ConnectAsync before you publish or subscribe.

Worker/Program.cs
using System.Text;
using KubeMQ.Sdk.Client;
using KubeMQ.Sdk.Events;

var builder = Host.CreateApplicationBuilder(args);
builder.AddServiceDefaults();
builder.AddKubeMQClient("messaging");

var host = builder.Build();
var client = host.Services.GetRequiredService<IKubeMQClient>();
var logger = host.Services.GetRequiredService<ILogger<Program>>();

await client.ConnectAsync();

await client.SendEventAsync(new EventMessage
{
    Channel = "events.fanout",
    Body = Encoding.UTF8.GetBytes("Hello from a worker"),
});

await host.RunAsync();

Was this page helpful?

On this page