diff --git a/docs/guide/migrating-to-wolverine.md b/docs/guide/migrating-to-wolverine.md index b34cbca67..610fc61cf 100644 --- a/docs/guide/migrating-to-wolverine.md +++ b/docs/guide/migrating-to-wolverine.md @@ -688,129 +688,6 @@ opts.Policies.RegisterInteropMessageAssembly(typeof(SharedMessages).Assembly); Wolverine detects message types from standard NServiceBus headers. You may need [message type aliases](/guide/messages#message-type-name-or-alias) to bridge naming differences. See the full [interoperability guide](/tutorials/interop#interop-with-nservicebus). -### NServiceBus Shim Interfaces - -Wolverine provides shim interfaces in the `Wolverine.Shims.NServiceBus` namespace that mimic the core NServiceBus -API surface while delegating to Wolverine's `IMessageBus` and `IMessageContext` under the hood. These shims let -you migrate handler code incrementally without rewriting every handler signature at once. - -::: tip -The shim interfaces are included in the core Wolverine NuGet package -- no additional packages are needed. -While these shims ease migration, the Wolverine team recommends eventually moving to Wolverine's native -convention-based handlers and pure function style for the best developer experience. -::: - -#### Automatic Handler Discovery - -Wolverine automatically discovers classes implementing `IHandleMessages` during its normal -[handler discovery](/guide/handlers/discovery) assembly scanning -- no explicit registration is needed. -The `IMessageHandlerContext` parameter in `Handle(T message, IMessageHandlerContext context)` is -automatically resolved via Wolverine's built-in code generation. - -Just make sure the assembly containing your `IHandleMessages` implementations is included in -Wolverine's discovery. By default, Wolverine scans the application assembly and any assemblies -explicitly added via `opts.Discovery.IncludeAssembly()`. See the -[handler discovery documentation](/guide/handlers/discovery) for more details on controlling which -assemblies are scanned. - -#### DI Registration for Non-Handler Interfaces - -If you need to inject NServiceBus shim interfaces (`IMessageSession`, `IEndpointInstance`, -`IUniformSession`, `ITransactionalSession`) into services outside of message handlers via -constructor injection, register them with: - -```csharp -builder.Host.UseWolverine(opts => -{ - opts.UseNServiceBusShims(); - - // Your Wolverine configuration... -}); -``` - -#### Available Interfaces - -| NServiceBus Shim | Delegates To | Purpose | -|-----------------|-------------|---------| -| `IMessageSession` | `IMessageBus` | Send/Publish outside of handlers | -| `IEndpointInstance` | `IMessageBus` + `IHost` | Running endpoint with lifecycle | -| `IMessageHandlerContext` | `IMessageContext` | Send/Publish/Reply inside handlers | -| `IUniformSession` | `IMessageBus` | Unified Send/Publish (inside or outside handlers) | -| `ITransactionalSession` | `IMessageBus` | Transactional Send/Publish (Open/Commit are obsolete) | -| `IHandleMessages` | `IWolverineHandler` | Handler discovery marker | - -#### Using IHandleMessages\ - -The `IHandleMessages` shim extends `IWolverineHandler`, so implementing it automatically registers your -handler with Wolverine's handler discovery: - -```csharp -using Wolverine.Shims.NServiceBus; - -// This handler is discovered by Wolverine via the IWolverineHandler marker -public class OrderHandler : IHandleMessages -{ - public async Task Handle(PlaceOrder message, IMessageHandlerContext context) - { - // context.Send, context.Publish, context.Reply all delegate to Wolverine - await context.Publish(new OrderPlaced(message.OrderId)); - await context.Reply(new PlaceOrderResponse { Success = true }); - } -} -``` - -#### Using IMessageSession / IEndpointInstance - -Inject `IMessageSession` or `IEndpointInstance` to send and publish messages outside of handlers: - -```csharp -using Wolverine.Shims.NServiceBus; - -public class OrderController : ControllerBase -{ - private readonly IMessageSession _session; - - public OrderController(IMessageSession session) => _session = session; - - [HttpPost] - public async Task PlaceOrder(PlaceOrderRequest request) - { - await _session.Send(new PlaceOrder(request.OrderId)); - return Accepted(); - } -} -``` - -#### NServiceBus-Style Options - -The shims include `SendOptions`, `PublishOptions`, and `ReplyOptions` classes that map to Wolverine's -`DeliveryOptions`: - -```csharp -var options = new SendOptions(); -options.SetDestination("remote-endpoint"); // routes to a named endpoint -options.SetHeader("tenant-id", "acme"); // adds a header -options.DelayDeliveryWith(TimeSpan.FromMinutes(5)); // schedules delivery - -await session.Send(new PlaceOrder("ABC-123"), options); -``` - -#### ITransactionalSession - -`ITransactionalSession` delegates `Send` and `Publish` to `IMessageBus`. The `Open()` and `Commit()` -lifecycle methods are marked `[Obsolete]` and throw `NotSupportedException` because Wolverine handles -transactional messaging automatically via its built-in [outbox](/guide/durability/): - -```csharp -// These methods are obsolete -- just delete the calls -// session.Open(); // throws NotSupportedException -// session.Commit(); // throws NotSupportedException - -// Send and Publish work normally -await session.Send(new PlaceOrder("ABC-123")); -await session.Publish(new OrderPlaced("ABC-123")); -``` - ### Migration Checklist **Phase 1: Coexistence** diff --git a/src/Testing/CoreTests/Shims/nservicebus_end_to_end.cs b/src/Testing/CoreTests/Shims/nservicebus_end_to_end.cs deleted file mode 100644 index c667150af..000000000 --- a/src/Testing/CoreTests/Shims/nservicebus_end_to_end.cs +++ /dev/null @@ -1,138 +0,0 @@ -using JasperFx.Core.Reflection; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Hosting; -using Wolverine.ComplianceTests; -using Wolverine.Runtime.Handlers; -using Wolverine.Shims.NServiceBus; -using Wolverine.Tracking; -using Xunit; -using Xunit.Abstractions; - -namespace CoreTests.Shims; - -public class nservicebus_end_to_end : IAsyncLifetime -{ - private readonly ITestOutputHelper _output; - private IHost _host = null!; - - public nservicebus_end_to_end(ITestOutputHelper output) - { - _output = output; - } - - public async Task InitializeAsync() - { - _host = await Host.CreateDefaultBuilder() - .UseWolverine(opts => - { - opts.UseNServiceBusShims(); - - opts.IncludeType(); - opts.IncludeType(); - }) - .StartAsync(); - } - - public async Task DisposeAsync() - { - await _host.StopAsync(); - _host.Dispose(); - } - - [Fact] - public async Task handler_handles_message_and_publishes_cascading_event() - { - NsbSubmitOrderHandler.Reset(); - NsbOrderSubmittedCascadeHandler.Reset(); - - var session = await _host.InvokeMessageAndWaitAsync(new NsbSubmitOrder("ORD-101")); - - NsbSubmitOrderHandler.LastOrderId.ShouldBe("ORD-101"); - NsbOrderSubmittedCascadeHandler.LastOrderId.ShouldBe("ORD-101"); - } - - [Fact] - public async Task handler_receives_message_handler_context() - { - NsbSubmitOrderHandler.Reset(); - - await _host.InvokeMessageAndWaitAsync(new NsbSubmitOrder("ORD-102")); - - NsbSubmitOrderHandler.LastOrderId.ShouldBe("ORD-102"); - NsbSubmitOrderHandler.ReceivedContext.ShouldBeTrue(); - } - - [Fact] - public void print_generated_code_for_handler() - { - // Force code generation by resolving the handler - _host.GetRuntime().Handlers.HandlerFor(); - - var graph = _host.Services.GetRequiredService(); - var chain = graph.ChainFor(); - chain.ShouldNotBeNull(); - - _output.WriteLine("=== Generated Code for NsbSubmitOrder (NServiceBus IHandleMessages) ==="); - _output.WriteLine(chain.SourceCode); - } - - [Fact] - public void print_generated_code_for_cascaded_handler() - { - // Force code generation by resolving the handler - _host.GetRuntime().Handlers.HandlerFor(); - - var graph = _host.Services.GetRequiredService(); - var chain = graph.ChainFor(); - chain.ShouldNotBeNull(); - - _output.WriteLine("=== Generated Code for NsbOrderSubmitted cascade handler ==="); - _output.WriteLine(chain.SourceCode); - } -} - -// --- NServiceBus shim message types --- - -public record NsbSubmitOrder(string OrderId); - -public record NsbOrderSubmitted(string OrderId); - -// --- NServiceBus IHandleMessages handler --- - -public class NsbSubmitOrderHandler : IHandleMessages -{ - public static string? LastOrderId; - public static bool ReceivedContext; - - public static void Reset() - { - LastOrderId = null; - ReceivedContext = false; - } - - public async Task Handle(NsbSubmitOrder message, IMessageHandlerContext context) - { - LastOrderId = message.OrderId; - ReceivedContext = true; - - // Publish a cascading event via the IMessageHandlerContext - await context.Publish(new NsbOrderSubmitted(message.OrderId)); - } -} - -// --- Handler for the cascaded event --- - -public class NsbOrderSubmittedCascadeHandler -{ - public static string? LastOrderId; - - public static void Reset() - { - LastOrderId = null; - } - - public void Handle(NsbOrderSubmitted message) - { - LastOrderId = message.OrderId; - } -} diff --git a/src/Testing/CoreTests/Shims/nservicebus_shim_tests.cs b/src/Testing/CoreTests/Shims/nservicebus_shim_tests.cs deleted file mode 100644 index 33d2bf02c..000000000 --- a/src/Testing/CoreTests/Shims/nservicebus_shim_tests.cs +++ /dev/null @@ -1,470 +0,0 @@ -using NSubstitute; -using Wolverine.Shims.NServiceBus; -using Xunit; - -namespace CoreTests.Shims; - -public class nservicebus_options_tests -{ - [Fact] - public void send_options_sets_headers() - { - var options = new SendOptions(); - options.SetHeader("key1", "value1"); - options.SetHeader("key2", "value2"); - - var delivery = options.ToDeliveryOptions(); - - delivery.Headers["key1"].ShouldBe("value1"); - delivery.Headers["key2"].ShouldBe("value2"); - } - - [Fact] - public void send_options_sets_destination() - { - var options = new SendOptions(); - options.SetDestination("my-endpoint"); - - options.Destination.ShouldBe("my-endpoint"); - } - - [Fact] - public void send_options_delay_delivery() - { - var options = new SendOptions(); - options.DelayDeliveryWith(TimeSpan.FromMinutes(5)); - - var delivery = options.ToDeliveryOptions(); - - delivery.ScheduleDelay.ShouldBe(TimeSpan.FromMinutes(5)); - delivery.ScheduledTime.ShouldBeNull(); - } - - [Fact] - public void send_options_do_not_deliver_before() - { - var scheduledTime = DateTimeOffset.UtcNow.AddHours(1); - var options = new SendOptions(); - options.DoNotDeliverBefore(scheduledTime); - - var delivery = options.ToDeliveryOptions(); - - delivery.ScheduledTime.ShouldBe(scheduledTime); - delivery.ScheduleDelay.ShouldBeNull(); - } - - [Fact] - public void send_options_delay_clears_scheduled_time() - { - var options = new SendOptions(); - options.DoNotDeliverBefore(DateTimeOffset.UtcNow.AddHours(1)); - options.DelayDeliveryWith(TimeSpan.FromMinutes(5)); - - var delivery = options.ToDeliveryOptions(); - - delivery.ScheduleDelay.ShouldBe(TimeSpan.FromMinutes(5)); - delivery.ScheduledTime.ShouldBeNull(); - } - - [Fact] - public void publish_options_sets_headers() - { - var options = new PublishOptions(); - options.SetHeader("event-type", "created"); - - var delivery = options.ToDeliveryOptions(); - - delivery.Headers["event-type"].ShouldBe("created"); - } - - [Fact] - public void reply_options_sets_headers() - { - var options = new ReplyOptions(); - options.SetHeader("reply-key", "reply-value"); - - var delivery = options.ToDeliveryOptions(); - - delivery.Headers["reply-key"].ShouldBe("reply-value"); - } - - [Fact] - public void get_headers_returns_empty_when_none_set() - { - var options = new SendOptions(); - options.GetHeaders().Count.ShouldBe(0); - } -} - -public class wolverine_message_session_tests -{ - private readonly IMessageBus _bus; - private readonly WolverineMessageSession _session; - - public wolverine_message_session_tests() - { - _bus = Substitute.For(); - _session = new WolverineMessageSession(_bus); - } - - [Fact] - public async Task send_delegates_to_bus_send_async() - { - var message = new TestNsbCommand("hello"); - - await _session.Send(message); - - await _bus.Received(1).SendAsync(message, null); - } - - [Fact] - public async Task send_with_options_delegates_with_delivery_options() - { - var message = new TestNsbCommand("hello"); - var options = new SendOptions(); - options.SetHeader("key", "value"); - - await _session.Send(message, options); - - await _bus.Received(1).SendAsync(message, - Arg.Is(d => d.Headers["key"] == "value")); - } - - [Fact] - public async Task send_with_destination_uses_endpoint() - { - var message = new TestNsbCommand("hello"); - var options = new SendOptions(); - options.SetDestination("remote-endpoint"); - - var endpoint = Substitute.For(); - _bus.EndpointFor("remote-endpoint").Returns(endpoint); - - await _session.Send(message, options); - - await endpoint.Received(1).SendAsync(message, Arg.Any()); - await _bus.DidNotReceive().SendAsync(Arg.Any(), Arg.Any()); - } - - [Fact] - public async Task publish_delegates_to_bus_publish_async() - { - var message = new TestNsbEvent("created"); - - await _session.Publish(message); - - await _bus.Received(1).PublishAsync(message, null); - } - - [Fact] - public async Task publish_with_options_delegates_with_delivery_options() - { - var message = new TestNsbEvent("created"); - var options = new PublishOptions(); - options.SetHeader("event-source", "test"); - - await _session.Publish(message, options); - - await _bus.Received(1).PublishAsync(message, - Arg.Is(d => d.Headers["event-source"] == "test")); - } -} - -public class wolverine_endpoint_instance_tests -{ - private readonly IMessageBus _bus; - private readonly Microsoft.Extensions.Hosting.IHost _host; - private readonly WolverineEndpointInstance _instance; - - public wolverine_endpoint_instance_tests() - { - _bus = Substitute.For(); - _host = Substitute.For(); - _instance = new WolverineEndpointInstance(_bus, _host); - } - - [Fact] - public async Task send_delegates_to_bus() - { - var message = new TestNsbCommand("hello"); - - await _instance.Send(message); - - await _bus.Received(1).SendAsync(message, null); - } - - [Fact] - public async Task publish_delegates_to_bus() - { - var message = new TestNsbEvent("created"); - - await _instance.Publish(message); - - await _bus.Received(1).PublishAsync(message, null); - } - - [Fact] - public async Task stop_delegates_to_host() - { - await _instance.Stop(); - - await _host.Received(1).StopAsync(Arg.Any()); - } - - [Fact] - public async Task send_with_destination_uses_endpoint() - { - var message = new TestNsbCommand("hello"); - var options = new SendOptions(); - options.SetDestination("remote"); - - var endpoint = Substitute.For(); - _bus.EndpointFor("remote").Returns(endpoint); - - await _instance.Send(message, options); - - await endpoint.Received(1).SendAsync(message, Arg.Any()); - } -} - -public class wolverine_message_handler_context_tests -{ - private readonly IMessageContext _context; - private readonly WolverineMessageHandlerContext _handlerContext; - - public wolverine_message_handler_context_tests() - { - _context = Substitute.For(); - _handlerContext = new WolverineMessageHandlerContext(_context); - } - - [Fact] - public void message_id_returns_envelope_id() - { - var envelope = new Envelope { Id = Guid.Parse("12345678-1234-1234-1234-123456789012") }; - _context.Envelope.Returns(envelope); - - _handlerContext.MessageId.ShouldBe("12345678-1234-1234-1234-123456789012"); - } - - [Fact] - public void message_id_returns_empty_when_no_envelope() - { - _context.Envelope.Returns((Envelope?)null); - - _handlerContext.MessageId.ShouldBe(string.Empty); - } - - [Fact] - public void reply_to_address_returns_envelope_reply_uri() - { - var envelope = new Envelope { ReplyUri = new Uri("tcp://localhost:1234") }; - _context.Envelope.Returns(envelope); - - _handlerContext.ReplyToAddress.ShouldStartWith("tcp://localhost:1234"); - } - - [Fact] - public void reply_to_address_returns_null_when_no_reply_uri() - { - var envelope = new Envelope(); - _context.Envelope.Returns(envelope); - - _handlerContext.ReplyToAddress.ShouldBeNull(); - } - - [Fact] - public void message_headers_returns_envelope_headers() - { - var envelope = new Envelope(); - envelope.Headers["key1"] = "value1"; - _context.Envelope.Returns(envelope); - - _handlerContext.MessageHeaders["key1"].ShouldBe("value1"); - } - - [Fact] - public void message_headers_returns_empty_when_no_envelope() - { - _context.Envelope.Returns((Envelope?)null); - - _handlerContext.MessageHeaders.Count.ShouldBe(0); - } - - [Fact] - public void correlation_id_delegates_to_context() - { - _context.CorrelationId.Returns("my-correlation-id"); - - _handlerContext.CorrelationId.ShouldBe("my-correlation-id"); - } - - [Fact] - public async Task send_delegates_to_context_send_async() - { - var message = new TestNsbCommand("hello"); - - await _handlerContext.Send(message); - - await _context.Received(1).SendAsync(message, null); - } - - [Fact] - public async Task send_with_destination_uses_endpoint() - { - var message = new TestNsbCommand("hello"); - var options = new SendOptions(); - options.SetDestination("remote"); - - var endpoint = Substitute.For(); - _context.EndpointFor("remote").Returns(endpoint); - - await _handlerContext.Send(message, options); - - await endpoint.Received(1).SendAsync(message, Arg.Any()); - } - - [Fact] - public async Task publish_delegates_to_context_publish_async() - { - var message = new TestNsbEvent("created"); - - await _handlerContext.Publish(message); - - await _context.Received(1).PublishAsync(message, null); - } - - [Fact] - public async Task reply_delegates_to_respond_to_sender() - { - var message = new TestNsbResponse("ok"); - - await _handlerContext.Reply(message); - - await _context.Received(1).RespondToSenderAsync(message); - } - - [Fact] - public async Task forward_current_message_sends_to_destination() - { - var originalMessage = new TestNsbCommand("forward-me"); - var envelope = new Envelope(originalMessage); - _context.Envelope.Returns(envelope); - - var endpoint = Substitute.For(); - _context.EndpointFor("other-endpoint").Returns(endpoint); - - await _handlerContext.ForwardCurrentMessageTo("other-endpoint"); - - await endpoint.Received(1).SendAsync(originalMessage, Arg.Any()); - } - - [Fact] - public async Task forward_current_message_throws_when_no_envelope() - { - _context.Envelope.Returns((Envelope?)null); - - await Should.ThrowAsync(() => - _handlerContext.ForwardCurrentMessageTo("other-endpoint")); - } -} - -public class wolverine_uniform_session_tests -{ - private readonly IMessageBus _bus; - private readonly WolverineUniformSession _session; - - public wolverine_uniform_session_tests() - { - _bus = Substitute.For(); - _session = new WolverineUniformSession(_bus); - } - - [Fact] - public async Task send_delegates_to_bus() - { - var message = new TestNsbCommand("hello"); - - await _session.Send(message); - - await _bus.Received(1).SendAsync(message, null); - } - - [Fact] - public async Task publish_delegates_to_bus() - { - var message = new TestNsbEvent("created"); - - await _session.Publish(message); - - await _bus.Received(1).PublishAsync(message, null); - } - - [Fact] - public async Task send_with_destination_uses_endpoint() - { - var message = new TestNsbCommand("hello"); - var options = new SendOptions(); - options.SetDestination("target"); - - var endpoint = Substitute.For(); - _bus.EndpointFor("target").Returns(endpoint); - - await _session.Send(message, options); - - await endpoint.Received(1).SendAsync(message, Arg.Any()); - } -} - -public class wolverine_transactional_session_tests -{ - private readonly IMessageBus _bus; - private readonly WolverineTransactionalSession _session; - - public wolverine_transactional_session_tests() - { - _bus = Substitute.For(); - _session = new WolverineTransactionalSession(_bus); - } - - [Fact] - public async Task send_delegates_to_bus() - { - var message = new TestNsbCommand("hello"); - - await _session.Send(message); - - await _bus.Received(1).SendAsync(message, null); - } - - [Fact] - public async Task publish_delegates_to_bus() - { - var message = new TestNsbEvent("created"); - - await _session.Publish(message); - - await _bus.Received(1).PublishAsync(message, null); - } - - [Fact] - public async Task open_throws_not_supported() - { -#pragma warning disable CS0618 // Obsolete - await Should.ThrowAsync(() => _session.Open()); -#pragma warning restore CS0618 - } - - [Fact] - public async Task commit_throws_not_supported() - { -#pragma warning disable CS0618 // Obsolete - await Should.ThrowAsync(() => _session.Commit()); -#pragma warning restore CS0618 - } -} - -// Test message types -public record TestNsbCommand(string Data); -public record TestNsbEvent(string Data); -public record TestNsbResponse(string Data); diff --git a/src/Wolverine/Shims/NServiceBus/ExtendableOptions.cs b/src/Wolverine/Shims/NServiceBus/ExtendableOptions.cs deleted file mode 100644 index 3ced98eb3..000000000 --- a/src/Wolverine/Shims/NServiceBus/ExtendableOptions.cs +++ /dev/null @@ -1,50 +0,0 @@ -namespace Wolverine.Shims.NServiceBus; - -/// -/// Base class for NServiceBus-compatible message options. -/// Maps internally to Wolverine's . -/// -public abstract class ExtendableOptions -{ - private Dictionary? _headers; - - /// - /// Sets a header key/value pair on the outgoing message. - /// - public void SetHeader(string key, string value) - { - _headers ??= new Dictionary(); - _headers[key] = value; - } - - /// - /// Gets all headers set on this options instance. - /// - public IReadOnlyDictionary GetHeaders() - { - return _headers ?? (IReadOnlyDictionary)new Dictionary(); - } - - /// - /// Sets the message identity for this options instance. - /// - public string? MessageId { get; set; } - - /// - /// Converts these NServiceBus-compatible options to Wolverine's . - /// - internal virtual DeliveryOptions ToDeliveryOptions() - { - var options = new DeliveryOptions(); - - if (_headers is { Count: > 0 }) - { - foreach (var kvp in _headers) - { - options.Headers[kvp.Key] = kvp.Value; - } - } - - return options; - } -} diff --git a/src/Wolverine/Shims/NServiceBus/IEndpointInstance.cs b/src/Wolverine/Shims/NServiceBus/IEndpointInstance.cs deleted file mode 100644 index bd5df1725..000000000 --- a/src/Wolverine/Shims/NServiceBus/IEndpointInstance.cs +++ /dev/null @@ -1,15 +0,0 @@ -namespace Wolverine.Shims.NServiceBus; - -/// -/// NServiceBus-compatible interface representing a running endpoint instance. -/// Extends with lifecycle management. -/// Delegates to Wolverine's . -/// -public interface IEndpointInstance : IMessageSession -{ - /// - /// Stops the endpoint instance. - /// Maps to stopping the underlying host. - /// - Task Stop(); -} diff --git a/src/Wolverine/Shims/NServiceBus/IHandleMessages.cs b/src/Wolverine/Shims/NServiceBus/IHandleMessages.cs deleted file mode 100644 index 1318be93b..000000000 --- a/src/Wolverine/Shims/NServiceBus/IHandleMessages.cs +++ /dev/null @@ -1,17 +0,0 @@ -namespace Wolverine.Shims.NServiceBus; - -/// -/// NServiceBus-compatible message handler interface. -/// Implementing this interface marks the class for Wolverine's handler discovery -/// via . -/// -/// The message type to handle -public interface IHandleMessages : IWolverineHandler -{ - /// - /// Handles a message of type . - /// - /// The message to handle - /// The handler context providing access to message metadata and messaging operations - Task Handle(T message, IMessageHandlerContext context); -} diff --git a/src/Wolverine/Shims/NServiceBus/IMessageHandlerContext.cs b/src/Wolverine/Shims/NServiceBus/IMessageHandlerContext.cs deleted file mode 100644 index 4bffc0b92..000000000 --- a/src/Wolverine/Shims/NServiceBus/IMessageHandlerContext.cs +++ /dev/null @@ -1,57 +0,0 @@ -namespace Wolverine.Shims.NServiceBus; - -/// -/// NServiceBus-compatible interface available during message handling. -/// Provides access to message metadata and the ability to send, publish, and reply. -/// Delegates to Wolverine's . -/// -public interface IMessageHandlerContext -{ - /// - /// The unique identifier of the message currently being handled. - /// Maps to . - /// - string MessageId { get; } - - /// - /// The address to which replies should be sent. - /// Maps to . - /// - string? ReplyToAddress { get; } - - /// - /// The headers of the message currently being handled. - /// Maps to . - /// - IReadOnlyDictionary MessageHeaders { get; } - - /// - /// The correlation identifier for the current message workflow. - /// Maps to . - /// - string? CorrelationId { get; } - - /// - /// Sends a command message. - /// Maps to . - /// - Task Send(object message, SendOptions? options = null); - - /// - /// Publishes an event message. - /// Maps to . - /// - Task Publish(object message, PublishOptions? options = null); - - /// - /// Sends a reply back to the originator of the current message. - /// Maps to . - /// - Task Reply(object message, ReplyOptions? options = null); - - /// - /// Sends the current message to a different endpoint for processing. - /// Maps to sending the current message body to the specified destination. - /// - Task ForwardCurrentMessageTo(string destination); -} diff --git a/src/Wolverine/Shims/NServiceBus/IMessageSession.cs b/src/Wolverine/Shims/NServiceBus/IMessageSession.cs deleted file mode 100644 index 72823699f..000000000 --- a/src/Wolverine/Shims/NServiceBus/IMessageSession.cs +++ /dev/null @@ -1,20 +0,0 @@ -namespace Wolverine.Shims.NServiceBus; - -/// -/// NServiceBus-compatible interface for sending and publishing messages outside of a message handler. -/// Delegates to Wolverine's . -/// -public interface IMessageSession -{ - /// - /// Sends a command message. In NServiceBus, Send is for commands (point-to-point). - /// Maps to . - /// - Task Send(object message, SendOptions? options = null); - - /// - /// Publishes an event message. In NServiceBus, Publish is for events (pub-sub). - /// Maps to . - /// - Task Publish(object message, PublishOptions? options = null); -} diff --git a/src/Wolverine/Shims/NServiceBus/ITransactionalSession.cs b/src/Wolverine/Shims/NServiceBus/ITransactionalSession.cs deleted file mode 100644 index 865ed2f91..000000000 --- a/src/Wolverine/Shims/NServiceBus/ITransactionalSession.cs +++ /dev/null @@ -1,22 +0,0 @@ -namespace Wolverine.Shims.NServiceBus; - -/// -/// NServiceBus-compatible transactional session interface. -/// Extends with transaction lifecycle. -/// Wolverine handles transactional messaging automatically, so the Open/Commit -/// methods are obsolete and will throw . -/// -public interface ITransactionalSession : IUniformSession -{ - /// - /// Opens the transactional session. - /// - [Obsolete("Wolverine handles transactions automatically. Delete this usage.")] - Task Open(); - - /// - /// Commits the transactional session. - /// - [Obsolete("Wolverine handles transactions automatically. Delete this usage.")] - Task Commit(); -} diff --git a/src/Wolverine/Shims/NServiceBus/IUniformSession.cs b/src/Wolverine/Shims/NServiceBus/IUniformSession.cs deleted file mode 100644 index aa3969f24..000000000 --- a/src/Wolverine/Shims/NServiceBus/IUniformSession.cs +++ /dev/null @@ -1,21 +0,0 @@ -namespace Wolverine.Shims.NServiceBus; - -/// -/// NServiceBus-compatible unified interface for sending and publishing that works -/// both inside and outside of message handlers. -/// Delegates to Wolverine's . -/// -public interface IUniformSession -{ - /// - /// Sends a command message. - /// Maps to . - /// - Task Send(object message, SendOptions? options = null); - - /// - /// Publishes an event message. - /// Maps to . - /// - Task Publish(object message, PublishOptions? options = null); -} diff --git a/src/Wolverine/Shims/NServiceBus/MessageHandlerContextVariableSource.cs b/src/Wolverine/Shims/NServiceBus/MessageHandlerContextVariableSource.cs deleted file mode 100644 index f04273a6c..000000000 --- a/src/Wolverine/Shims/NServiceBus/MessageHandlerContextVariableSource.cs +++ /dev/null @@ -1,51 +0,0 @@ -using JasperFx.CodeGeneration; -using JasperFx.CodeGeneration.Frames; -using JasperFx.CodeGeneration.Model; -using JasperFx.Core.Reflection; - -namespace Wolverine.Shims.NServiceBus; - -/// -/// Code generation variable source that creates -/// instances from the current . -/// This eliminates the need for service location when resolving -/// in handler methods. -/// -internal class MessageHandlerContextVariableSource : IVariableSource -{ - public bool Matches(Type type) - { - return type == typeof(IMessageHandlerContext); - } - - public Variable Create(Type type) - { - return new MessageHandlerContextFrame().Variable; - } -} - -internal class MessageHandlerContextFrame : SyncFrame -{ - private Variable? _context; - - public MessageHandlerContextFrame() - { - Variable = new Variable(typeof(IMessageHandlerContext), this); - } - - public Variable Variable { get; } - - public override IEnumerable FindVariables(IMethodVariables chain) - { - _context = chain.FindVariable(typeof(IMessageContext)); - yield return _context; - } - - public override void GenerateCode(GeneratedMethod method, ISourceWriter writer) - { - writer.WriteLine( - $"var {Variable.Usage} = new {typeof(WolverineMessageHandlerContext).FullNameInCode()}({_context!.Usage});"); - - Next?.GenerateCode(method, writer); - } -} diff --git a/src/Wolverine/Shims/NServiceBus/NServiceBusShimExtensions.cs b/src/Wolverine/Shims/NServiceBus/NServiceBusShimExtensions.cs deleted file mode 100644 index a08e91cb9..000000000 --- a/src/Wolverine/Shims/NServiceBus/NServiceBusShimExtensions.cs +++ /dev/null @@ -1,36 +0,0 @@ -using Microsoft.Extensions.DependencyInjection; - -namespace Wolverine.Shims.NServiceBus; - -/// -/// Extension methods to register NServiceBus shim interfaces with Wolverine. -/// -public static class NServiceBusShimExtensions -{ - /// - /// Registers NServiceBus shim DI services for constructor injection. - /// is automatically resolved in handler methods - /// via code generation and does not require this call. - /// This registers , , - /// , and for - /// constructor injection in services outside of message handlers. - /// - public static WolverineOptions UseNServiceBusShims(this WolverineOptions options) - { - options.Services.AddScoped(sp => - new WolverineMessageSession(sp.GetRequiredService())); - - options.Services.AddScoped(sp => - new WolverineEndpointInstance( - sp.GetRequiredService(), - sp.GetRequiredService())); - - options.Services.AddScoped(sp => - new WolverineUniformSession(sp.GetRequiredService())); - - options.Services.AddScoped(sp => - new WolverineTransactionalSession(sp.GetRequiredService())); - - return options; - } -} diff --git a/src/Wolverine/Shims/NServiceBus/PublishOptions.cs b/src/Wolverine/Shims/NServiceBus/PublishOptions.cs deleted file mode 100644 index 1419fd59e..000000000 --- a/src/Wolverine/Shims/NServiceBus/PublishOptions.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace Wolverine.Shims.NServiceBus; - -/// -/// NServiceBus-compatible options for publishing an event message. -/// Maps internally to Wolverine's . -/// -public class PublishOptions : ExtendableOptions -{ -} diff --git a/src/Wolverine/Shims/NServiceBus/ReplyOptions.cs b/src/Wolverine/Shims/NServiceBus/ReplyOptions.cs deleted file mode 100644 index 03767627f..000000000 --- a/src/Wolverine/Shims/NServiceBus/ReplyOptions.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace Wolverine.Shims.NServiceBus; - -/// -/// NServiceBus-compatible options for replying to the sender of the current message. -/// Maps internally to Wolverine's . -/// -public class ReplyOptions : ExtendableOptions -{ -} diff --git a/src/Wolverine/Shims/NServiceBus/SendOptions.cs b/src/Wolverine/Shims/NServiceBus/SendOptions.cs deleted file mode 100644 index 4009a0f3f..000000000 --- a/src/Wolverine/Shims/NServiceBus/SendOptions.cs +++ /dev/null @@ -1,62 +0,0 @@ -namespace Wolverine.Shims.NServiceBus; - -/// -/// NServiceBus-compatible options for sending a command message. -/// Maps internally to Wolverine's . -/// -public class SendOptions : ExtendableOptions -{ - /// - /// Sets the destination endpoint for this send operation. - /// Maps to Wolverine's . - /// - public string? Destination { get; set; } - - /// - /// Sets the destination endpoint for the send operation. - /// - public void SetDestination(string destination) - { - Destination = destination; - } - - /// - /// Delays the delivery of the message by the specified time span. - /// Maps to . - /// - public void DelayDeliveryWith(TimeSpan delay) - { - Delay = delay; - ScheduledTime = null; - } - - /// - /// Delays the delivery of the message until the specified time. - /// Maps to . - /// - public void DoNotDeliverBefore(DateTimeOffset at) - { - ScheduledTime = at; - Delay = null; - } - - internal TimeSpan? Delay { get; set; } - internal DateTimeOffset? ScheduledTime { get; set; } - - internal override DeliveryOptions ToDeliveryOptions() - { - var options = base.ToDeliveryOptions(); - - if (Delay.HasValue) - { - options.ScheduleDelay = Delay; - } - - if (ScheduledTime.HasValue) - { - options.ScheduledTime = ScheduledTime; - } - - return options; - } -} diff --git a/src/Wolverine/Shims/NServiceBus/WolverineEndpointInstance.cs b/src/Wolverine/Shims/NServiceBus/WolverineEndpointInstance.cs deleted file mode 100644 index 2ad8a82e6..000000000 --- a/src/Wolverine/Shims/NServiceBus/WolverineEndpointInstance.cs +++ /dev/null @@ -1,44 +0,0 @@ -using Microsoft.Extensions.Hosting; - -namespace Wolverine.Shims.NServiceBus; - -/// -/// Wolverine-backed implementation of . -/// Delegates messaging to and lifecycle to . -/// -public class WolverineEndpointInstance : IEndpointInstance -{ - private readonly IMessageBus _bus; - private readonly IHost _host; - - public WolverineEndpointInstance(IMessageBus bus, IHost host) - { - _bus = bus; - _host = host; - } - - public async Task Send(object message, SendOptions? options = null) - { - var deliveryOptions = options?.ToDeliveryOptions(); - - if (options?.Destination != null) - { - var endpoint = _bus.EndpointFor(options.Destination); - await endpoint.SendAsync(message, deliveryOptions); - } - else - { - await _bus.SendAsync(message, deliveryOptions); - } - } - - public async Task Publish(object message, PublishOptions? options = null) - { - await _bus.PublishAsync(message, options?.ToDeliveryOptions()); - } - - public async Task Stop() - { - await _host.StopAsync(); - } -} diff --git a/src/Wolverine/Shims/NServiceBus/WolverineMessageHandlerContext.cs b/src/Wolverine/Shims/NServiceBus/WolverineMessageHandlerContext.cs deleted file mode 100644 index b1f705dab..000000000 --- a/src/Wolverine/Shims/NServiceBus/WolverineMessageHandlerContext.cs +++ /dev/null @@ -1,60 +0,0 @@ -namespace Wolverine.Shims.NServiceBus; - -/// -/// Wolverine-backed implementation of . -/// Delegates all operations to . -/// -public class WolverineMessageHandlerContext : IMessageHandlerContext -{ - private readonly IMessageContext _context; - - public WolverineMessageHandlerContext(IMessageContext context) - { - _context = context; - } - - public string MessageId => _context.Envelope?.Id.ToString() ?? string.Empty; - - public string? ReplyToAddress => _context.Envelope?.ReplyUri?.ToString(); - - public IReadOnlyDictionary MessageHeaders => - _context.Envelope?.Headers ?? (IReadOnlyDictionary)new Dictionary(); - - public string? CorrelationId => _context.CorrelationId; - - public async Task Send(object message, SendOptions? options = null) - { - var deliveryOptions = options?.ToDeliveryOptions(); - - if (options?.Destination != null) - { - var endpoint = _context.EndpointFor(options.Destination); - await endpoint.SendAsync(message, deliveryOptions); - } - else - { - await _context.SendAsync(message, deliveryOptions); - } - } - - public async Task Publish(object message, PublishOptions? options = null) - { - await _context.PublishAsync(message, options?.ToDeliveryOptions()); - } - - public async Task Reply(object message, ReplyOptions? options = null) - { - await _context.RespondToSenderAsync(message); - } - - public async Task ForwardCurrentMessageTo(string destination) - { - if (_context.Envelope?.Message == null) - { - throw new InvalidOperationException("No current message to forward."); - } - - var endpoint = _context.EndpointFor(destination); - await endpoint.SendAsync(_context.Envelope.Message); - } -} diff --git a/src/Wolverine/Shims/NServiceBus/WolverineMessageSession.cs b/src/Wolverine/Shims/NServiceBus/WolverineMessageSession.cs deleted file mode 100644 index 87610e330..000000000 --- a/src/Wolverine/Shims/NServiceBus/WolverineMessageSession.cs +++ /dev/null @@ -1,35 +0,0 @@ -namespace Wolverine.Shims.NServiceBus; - -/// -/// Wolverine-backed implementation of . -/// Delegates all operations to . -/// -public class WolverineMessageSession : IMessageSession -{ - private readonly IMessageBus _bus; - - public WolverineMessageSession(IMessageBus bus) - { - _bus = bus; - } - - public async Task Send(object message, SendOptions? options = null) - { - var deliveryOptions = options?.ToDeliveryOptions(); - - if (options?.Destination != null) - { - var endpoint = _bus.EndpointFor(options.Destination); - await endpoint.SendAsync(message, deliveryOptions); - } - else - { - await _bus.SendAsync(message, deliveryOptions); - } - } - - public async Task Publish(object message, PublishOptions? options = null) - { - await _bus.PublishAsync(message, options?.ToDeliveryOptions()); - } -} diff --git a/src/Wolverine/Shims/NServiceBus/WolverineTransactionalSession.cs b/src/Wolverine/Shims/NServiceBus/WolverineTransactionalSession.cs deleted file mode 100644 index 74ae3b3db..000000000 --- a/src/Wolverine/Shims/NServiceBus/WolverineTransactionalSession.cs +++ /dev/null @@ -1,50 +0,0 @@ -namespace Wolverine.Shims.NServiceBus; - -/// -/// Wolverine-backed implementation of . -/// Delegates messaging to . -/// Open/Commit are not supported because Wolverine handles transactions automatically. -/// -public class WolverineTransactionalSession : ITransactionalSession -{ - private readonly IMessageBus _bus; - - public WolverineTransactionalSession(IMessageBus bus) - { - _bus = bus; - } - - public async Task Send(object message, SendOptions? options = null) - { - var deliveryOptions = options?.ToDeliveryOptions(); - - if (options?.Destination != null) - { - var endpoint = _bus.EndpointFor(options.Destination); - await endpoint.SendAsync(message, deliveryOptions); - } - else - { - await _bus.SendAsync(message, deliveryOptions); - } - } - - public async Task Publish(object message, PublishOptions? options = null) - { - await _bus.PublishAsync(message, options?.ToDeliveryOptions()); - } - - [Obsolete("Wolverine handles transactions automatically. Delete this usage.")] - public Task Open() - { - throw new NotSupportedException( - "Wolverine handles transactions automatically. Remove calls to Open()."); - } - - [Obsolete("Wolverine handles transactions automatically. Delete this usage.")] - public Task Commit() - { - throw new NotSupportedException( - "Wolverine handles transactions automatically. Remove calls to Commit()."); - } -} diff --git a/src/Wolverine/Shims/NServiceBus/WolverineUniformSession.cs b/src/Wolverine/Shims/NServiceBus/WolverineUniformSession.cs deleted file mode 100644 index 353cd3ad9..000000000 --- a/src/Wolverine/Shims/NServiceBus/WolverineUniformSession.cs +++ /dev/null @@ -1,35 +0,0 @@ -namespace Wolverine.Shims.NServiceBus; - -/// -/// Wolverine-backed implementation of . -/// Delegates all operations to . -/// -public class WolverineUniformSession : IUniformSession -{ - private readonly IMessageBus _bus; - - public WolverineUniformSession(IMessageBus bus) - { - _bus = bus; - } - - public async Task Send(object message, SendOptions? options = null) - { - var deliveryOptions = options?.ToDeliveryOptions(); - - if (options?.Destination != null) - { - var endpoint = _bus.EndpointFor(options.Destination); - await endpoint.SendAsync(message, deliveryOptions); - } - else - { - await _bus.SendAsync(message, deliveryOptions); - } - } - - public async Task Publish(object message, PublishOptions? options = null) - { - await _bus.PublishAsync(message, options?.ToDeliveryOptions()); - } -} diff --git a/src/Wolverine/WolverineOptions.cs b/src/Wolverine/WolverineOptions.cs index 419aac741..b68dd59b4 100644 --- a/src/Wolverine/WolverineOptions.cs +++ b/src/Wolverine/WolverineOptions.cs @@ -122,9 +122,6 @@ public WolverineOptions(string? assemblyName) CodeGeneration.Sources.Add(new Shims.MassTransit.ConsumeContextVariableSource()); CodeGeneration.Sources.Add(new Shims.MassTransit.MassTransitInterfaceVariableSource()); - // NServiceBus shim variable sources - CodeGeneration.Sources.Add(new Shims.NServiceBus.MessageHandlerContextVariableSource()); - CodeGeneration.Assemblies.Add(GetType().Assembly); if (assemblyName != null)