Skip to content

Add transport endpoint URI helpers for all supported transports (#2502)#2533

Merged
jeremydmiller merged 1 commit intoJasperFx:mainfrom
BlackChepo:feature/2502_uri_helper
Apr 17, 2026
Merged

Add transport endpoint URI helpers for all supported transports (#2502)#2533
jeremydmiller merged 1 commit intoJasperFx:mainfrom
BlackChepo:feature/2502_uri_helper

Conversation

@BlackChepo
Copy link
Copy Markdown
Contributor

Summary

Closes #2502

Adds a static <Transport>EndpointUri helper class to every supported transport package so users no longer have to hand-write raw URI strings when identifying endpoints.
Each helper exposes Uri-returning factory methods for every URI shape the transport's parser accepts, with consistent validation, XML docs, and URI-parser roundtrip tests.

Before:

options.PublishMessage<OrderCreated>()
       .ToUri(new Uri("rabbitmq://queue/orders"));

After:

options.PublishMessage<OrderCreated>()
       .ToUri(RabbitMqEndpointUri.Queue("orders"));

What's included

New helper classes (10 transports)

Package Class Methods
Wolverine.RabbitMQ RabbitMqEndpointUri Queue, Exchange, Topic(ex, key), Routing(ex, key)
Wolverine.Kafka KafkaEndpointUri Topic
Wolverine.AzureServiceBus AzureServiceBusEndpointUri Queue, Topic, Subscription(topic, sub)
Wolverine.AmazonSqs SqsEndpointUri Queue
Wolverine.AmazonSns SnsEndpointUri Topic
Wolverine.Redis RedisEndpointUri Stream, Stream(..., consumerGroup)
Wolverine.MQTT MqttEndpointUri Topic
Wolverine.Nats NatsEndpointUri Subject
Wolverine.Pulsar PulsarEndpointUri PersistentTopic, NonPersistentTopic, Topic(..., bool), Topic(string)
Wolverine.Pubsub GcpPubsubEndpointUri Topic(projectId, topicName)

Every method validates string inputs with ArgumentException.ThrowIfNullOrWhiteSpace and carries full XML documentation (<summary>, <param>, <returns>, <example>,
<exception>).

Migration of existing ad-hoc helpers

Two transports already shipped public URI builders. These are preserved with [Obsolete] attributes for backward compatibility:

Old New Migration
RedisTransport.BuildRedisStreamUri(...) RedisEndpointUri.Stream(...) One-line delegator. Obsolete.
PulsarEndpoint.UriFor(string topicPath) PulsarEndpointUri.Topic(string) One-line delegator. Obsolete.
PulsarEndpoint.UriFor(bool, tenant, ns, topic) (no delegator) Stays bit-exact. Obsolete. Returns a Pulsar-native topic path (persistent://...), which is a
different URI form from the Wolverine endpoint URI (pulsar://...) produced by PulsarEndpointUri. The obsolete message explains the non-delegation.

Internal library callers were rewritten where sensible:

  • PulsarTransport.EndpointFor and PulsarTransportExtensions now call PulsarEndpointUri.Topic directly.
  • PulsarListener's retry/DLQ topic builders still need the topic-path form for the native Pulsar client; those two call sites wrap the obsolete call with #pragma warning disable CS0618.

Behavioural note on PulsarEndpointUri.Topic(string)

The new canonical helper validates strictly: the input scheme must be persistent or non-persistent, and the path must contain exactly tenant/namespace/topic.
Previously-accepted malformed input (e.g. "http://..." or a Wolverine endpoint URI passed by mistake) now throws an ArgumentException at the helper instead of silently
producing a corrupt URI that only fails later in PulsarEndpoint.Parse. Callers passing well-formed Pulsar-native paths are unaffected.

Testing

  • One new test class per transport (<Transport>EndpointUriTests.cs), covering shape assertions, null/whitespace validation theories, and — where feasible without a live
    broker — a URI-parser roundtrip via transport.GetOrCreateEndpoint(uri). ~130 test cases total.
  • Additional compatibility tests in PulsarEndpointTests pin the deprecated UriFor behaviour:
    • uri_for_topic_string_handles_non_persistent_scheme
    • uri_for_topic_string_preserves_realistic_topic_names
    • uri_for_bool_produces_retry_suffix_path_used_by_pulsar_listener
    • uri_for_bool_produces_dlq_suffix_path_used_by_pulsar_listener

The last two lock down the exact URI format that PulsarListener passes to the native Pulsar client for retry and dead-letter topics, guarding against accidental
regressions in the interop-critical path.

Documentation

  • Added a ## URI reference section to every transport's Vitepress page under docs/guide/messaging/transports/, with a table mapping URI forms to helper calls and a short
    C# sample.
  • Redis and Pulsar pages carry a deprecation tip pointing users from BuildRedisStreamUri / UriFor to the new helpers.
  • The Redis DocumentationSamples and four incidentally-using Pulsar test files (InlinePulsarTransportComplianceTests, PulsarTransportComplianceTests,
    WithCloudEvents, endpoint_configuration) were migrated to the new helper.

Breaking changes

None for source compatibility. The deprecated [Obsolete] attributes are warnings (not errors), and all call sites that passed well-formed input continue to work.

Test plan

  • dotnet build wolverine.sln — 0 warnings, 0 errors from library code.
  • Fast-test pass for every transport's *EndpointUriTests (all 10 classes green).
  • Redis and Pulsar existing tests still pass (proves obsolete delegators preserve behaviour).
  • Vitepress docs build picks up the new "URI reference" sections without layout regression.

…erFx#2502)

Introduce <Transport>EndpointUri static helper classes for every built-in
transport so users no longer need to hand-write raw URI strings. Each
helper exposes Uri-returning factory methods that cover every URI shape
the transport's parser accepts, with ArgumentException validation on every
string parameter and XML documentation on every method.

New helpers:
- RabbitMqEndpointUri         (Queue, Exchange, Topic, Routing)
- KafkaEndpointUri            (Topic)
- AzureServiceBusEndpointUri  (Queue, Topic, Subscription)
- SqsEndpointUri              (Queue)
- SnsEndpointUri              (Topic)
- MqttEndpointUri             (Topic)
- NatsEndpointUri             (Subject)
- PulsarEndpointUri           (PersistentTopic, NonPersistentTopic,
                               Topic(..., bool), Topic(string))
- GcpPubsubEndpointUri        (Topic)
- RedisEndpointUri            (Stream, Stream with consumer group)

Migration of existing ad-hoc helpers:
- RedisTransport.BuildRedisStreamUri is now a [Obsolete] one-line
  delegator to RedisEndpointUri.Stream.
- PulsarEndpoint.UriFor(string) is now a [Obsolete] delegator to
  PulsarEndpointUri.Topic(string).
- PulsarEndpoint.UriFor(bool, tenant, ns, topic) stays bit-exact and is
  marked [Obsolete] without delegation: it returns a Pulsar-native topic
  path ("persistent://..."), which is a different URI form from the
  Wolverine endpoint URI ("pulsar://...") produced by PulsarEndpointUri.
  The obsolete message explains the non-delegation for future readers.
- Internal library callers that want endpoint URIs (PulsarTransport,
  PulsarTransportExtensions) now call PulsarEndpointUri.Topic directly.
- PulsarListener still needs the topic-path form for the native Pulsar
  client; its two call sites wrap the obsolete call with
  #pragma warning disable CS0618.

PulsarEndpointUri.Topic(string) validates strictly: the scheme must be
"persistent" or "non-persistent" and the path must contain exactly
tenant/namespace/topic. Previously-accepted malformed input (e.g.
"http://..." or a Wolverine endpoint URI) now throws an
ArgumentException at the helper instead of silently producing a corrupt
URI that only fails later in PulsarEndpoint.Parse.

Tests:
- One new test class per transport covering shape, validation, and
  (where feasible without a live broker) URI-parser roundtrip, totalling
  ~130 new test cases.
- Additional compatibility tests in PulsarEndpointTests pin the deprecated
  UriFor behaviour for non-persistent scheme input, realistic topic names
  with dots/dashes, and the -RETRY / -DLQ suffix patterns used by
  PulsarListener against the native Pulsar client.

Documentation:
- Added a "## URI reference" section to every transport's Vitepress docs
  page mapping URI forms to helper calls.
- Redis and Pulsar pages include a deprecation tip pointing users from
  BuildRedisStreamUri / UriFor to the new helpers.
- Redis DocumentationSamples and four Pulsar test files that used
  UriFor(string) incidentally were migrated to PulsarEndpointUri.Topic.
@jeremydmiller
Copy link
Copy Markdown
Member

@BlackChepo Thank you!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add helper methods for building Wolverine transport endpoint URIs

2 participants