--- title: "Apache ActiveMQ Artemis transport" description: "The BabelQueue.Artemis transport — a canonical-envelope publisher and a URN-routed AMQP 1.0 consumer over AMQPNetLite, on the framework-agnostic core." source: https://babelqueue.com/docs/babelqueue-dotnet/1.x/apache-activemq-artemis/ updated: 2026-06-14T00:00:00.000Z --- # Apache ActiveMQ Artemis transport `BabelQueue.Artemis` is an Apache ActiveMQ Artemis transport on the .NET core, built on **AMQP 1.0** (AMQPNetLite). It sends the [canonical envelope](/docs/spec/1.x/envelope/) as the message body with the [§7 projection](/docs/spec/1.x/broker-bindings/#apache-activemq-artemis), and consumes by routing each message to a handler by URN — so a message it produces is consumed by any other BabelQueue SDK, and vice-versa. Artemis gives the binding native settlement, scheduled delivery, a delivery counter and a dead-letter address, so it maps onto them rather than re-implementing. ## Install ```bash dotnet add package BabelQueue.Artemis ``` Requirements: **.NET 8**. It pulls `BabelQueue.Core` and `AMQPNetLite.Core` transitively. ## Produce ```csharp using Amqp; using BabelQueue.Artemis; var connection = new Connection(new Address("amqp://user:pass@localhost:5672")); var session = new Session(connection); var sender = new AmqpSenderLink(new SenderLink(session, "orders-sender", "orders"), "orders"); var id = await new ArtemisPublisher(sender) .PublishAsync("urn:babel:orders:created", new Dictionary { ["order_id"] = 1042 }); ``` `PublishAsync` returns the message `meta.id`; pass a `traceId` to continue a trace, or a `delay` (`TimeSpan`) for native AMQP scheduled delivery. ## Consume ```csharp using Amqp; using BabelQueue; using BabelQueue.Artemis; var receiver = new AmqpReceiverLink(new ReceiverLink(session, "orders-worker", "orders")); var dlq = new AmqpSenderLink(new SenderLink(session, "dlq-sender", "orders.dlq"), "orders.dlq"); var handlers = new Dictionary { ["urn:babel:orders:created"] = (envelope, message, ct) => { // envelope.Data, envelope.TraceId, envelope.Attempts ... return Task.CompletedTask; }, }; var options = new ArtemisConsumerOptions { DeadLetterSender = dlq, MaxTries = 3 }; var worker = new ArtemisConsumer(receiver, handlers, options); await worker.RunAsync(cancellationToken); // receive → process → Accept ``` A successful handler `Accept`s the message. A throwing handler `Release`s it (the broker redelivers and bumps `delivery-count`); once `MaxTries` is reached the envelope goes to `.dlq` with a `dead_letter` block. The consumer routes on the `x-opt-jms-type` annotation (falling back to the body URN). Unknown-URN strategy is one of `fail` / `delete` / `release` / `dead_letter`. `AmqpSenderLink` / `AmqpReceiverLink` wrap the AMQPNetLite links; the publisher and consumer depend on the `IAmqpSender` / `IAmqpReceiver` seams, so they unit-test against mocks with no broker. ## Contract mapping (§7) | Envelope | Apache ActiveMQ Artemis (AMQP 1.0) | | :--- | :--- | | body | message body (byte-identical across SDKs) | | `job` (URN) | `x-opt-jms-type` annotation → JMSType (consumer routes on this) | | `trace_id` | `correlation-id` → JMSCorrelationID | | `meta.created_at` | `creation-time` → JMSTimestamp (Unix ms) | | `meta.schema_version` | application property `bq_schema_version` | | `meta.lang` | application property `bq_source_lang` | | `attempts` | `max(body, delivery-count)` (AMQP counter is 0-based) | | reserve / ack | `Receive` → process → **`Accept`** | | retry / delay | `Release` redelivery · native `x-opt-delivery-time` | | dead-letter | `.dlq` + `dead_letter` block (alongside the native DLA) | The AMQP send/receive seams are mocked with Moq — no Artemis, no network. The envelope is unchanged (`schema_version` stays `1`); Apache ActiveMQ Artemis is purely additive.