From 4b109930dd6ab53250c0a221e8dd539e0662e01e Mon Sep 17 00:00:00 2001
From: hsnabszhdn <16090309+hsnabszhdn@users.noreply.github.com>
Date: Sun, 16 Mar 2025 08:32:31 +1100
Subject: [PATCH] docs: commit 'mdsnippets' changes
---
docs/guide/basics.md | 8 +--
docs/guide/command-line.md | 4 +-
docs/guide/configuration.md | 4 +-
docs/guide/diagnostics.md | 8 +--
docs/guide/durability/dead-letter-storage.md | 18 +++++-
docs/guide/durability/idempotency.md | 4 +-
docs/guide/durability/index.md | 4 +-
.../durability/marten/ancillary-stores.md | 4 +-
.../guide/durability/marten/event-sourcing.md | 58 ++++++++++++-------
docs/guide/durability/marten/operations.md | 6 +-
docs/guide/durability/marten/outbox.md | 4 +-
docs/guide/durability/marten/subscriptions.md | 4 +-
.../marten/transactional-middleware.md | 8 +--
docs/guide/durability/sagas.md | 12 ++--
docs/guide/extensions.md | 20 +++----
docs/guide/handlers/batching.md | 12 ++--
docs/guide/handlers/cascading.md | 44 +++++++-------
docs/guide/handlers/discovery.md | 35 ++++++++---
docs/guide/handlers/error-handling.md | 12 ++--
docs/guide/handlers/index.md | 44 +++++++-------
docs/guide/handlers/middleware.md | 40 ++++++-------
docs/guide/handlers/multi-tenancy.md | 4 +-
docs/guide/handlers/persistence.md | 4 +-
docs/guide/handlers/return-values.md | 16 ++---
docs/guide/handlers/side-effects.md | 12 ++--
docs/guide/handlers/sticky.md | 4 +-
docs/guide/handlers/timeout.md | 4 +-
docs/guide/http/endpoints.md | 18 +++---
docs/guide/http/index.md | 4 +-
docs/guide/http/integration.md | 14 ++---
docs/guide/http/marten.md | 17 ++++--
docs/guide/http/messaging.md | 20 +++----
docs/guide/http/metadata.md | 8 +--
docs/guide/http/middleware.md | 12 ++--
docs/guide/http/multi-tenancy.md | 20 +++----
docs/guide/http/policies.md | 8 +--
docs/guide/http/problemdetails.md | 4 +-
docs/guide/http/security.md | 4 +-
docs/guide/logging.md | 10 ++--
docs/guide/messages.md | 32 +++++-----
docs/guide/messaging/expiration.md | 2 +-
docs/guide/messaging/listeners.md | 4 +-
docs/guide/messaging/message-bus.md | 22 +++----
docs/guide/messaging/subscriptions.md | 24 ++++----
docs/guide/messaging/transports/local.md | 28 ++++-----
docs/guide/messaging/transports/mqtt.md | 17 ++----
.../rabbitmq/conventional-routing.md | 6 +-
.../transports/rabbitmq/deadletterqueues.md | 6 +-
.../messaging/transports/rabbitmq/index.md | 8 +--
.../transports/rabbitmq/interoperability.md | 12 ++--
.../transports/rabbitmq/listening.md | 4 +-
.../transports/rabbitmq/multiple-brokers.md | 2 +-
.../transports/rabbitmq/object-management.md | 41 +++++++++++--
.../transports/rabbitmq/publishing.md | 6 +-
.../messaging/transports/rabbitmq/topics.md | 18 ++----
docs/guide/messaging/transports/tcp.md | 8 +--
docs/guide/migration.md | 4 +-
docs/guide/runtime.md | 16 ++---
docs/guide/testing.md | 8 +--
docs/tutorials/cqrs-with-marten.md | 24 ++++----
docs/tutorials/from-mediatr.md | 4 +-
docs/tutorials/getting-started.md | 16 ++---
docs/tutorials/mediator.md | 20 +++----
docs/tutorials/middleware.md | 16 ++---
docs/tutorials/ping-pong.md | 28 ++++-----
docs/tutorials/railway-programming.md | 4 +-
66 files changed, 493 insertions(+), 423 deletions(-)
diff --git a/docs/guide/basics.md b/docs/guide/basics.md
index 29022f7ee..ee1ba1932 100644
--- a/docs/guide/basics.md
+++ b/docs/guide/basics.md
@@ -10,7 +10,7 @@ something happened. Just know that as far as Wolverine is concerned, those are r
Here's a couple simple samples:
-
+
```cs
// A "command" message
public record DebitAccount(long AccountId, decimal Amount);
@@ -18,14 +18,14 @@ public record DebitAccount(long AccountId, decimal Amount);
// An "event" message
public record AccountOverdrawn(long AccountId);
```
-snippet source | anchor
+snippet source | anchor
The next concept in Wolverine is a message handler, which is just a method that "knows" how to process an incoming message. Here's an extremely
simple example:
-
+
```cs
public static class DebitAccountHandler
{
@@ -35,7 +35,7 @@ public static class DebitAccountHandler
}
}
```
-snippet source | anchor
+snippet source | anchor
Wolverine can act as a completely local mediator tool that allows your code to invoke the handler for a message at any time without having
diff --git a/docs/guide/command-line.md b/docs/guide/command-line.md
index 60782c6b7..c2e73a456 100644
--- a/docs/guide/command-line.md
+++ b/docs/guide/command-line.md
@@ -5,7 +5,7 @@ tools. To get started, apply Oakton as the command line parser in your applicati
sample application bootstrapping from Wolverine's [Getting Started](/tutorials/getting-started):
-
+
```cs
using Oakton;
using Quickstart;
@@ -47,7 +47,7 @@ app.MapGet("/", () => Results.Redirect("/swagger"));
// your Wolverine application
return await app.RunOaktonCommands(args);
```
-snippet source | anchor
+snippet source | anchor
From this project's root in the command line terminal tool of your choice, type:
diff --git a/docs/guide/configuration.md b/docs/guide/configuration.md
index 505bed92f..5b3552f80 100644
--- a/docs/guide/configuration.md
+++ b/docs/guide/configuration.md
@@ -35,7 +35,7 @@ Below is a sample of adding Wolverine to an ASP.NET Core application that is boo
`WebApplicationBuilder`:
-
+
```cs
using Oakton;
using Quickstart;
@@ -77,7 +77,7 @@ app.MapGet("/", () => Results.Redirect("/swagger"));
// your Wolverine application
return await app.RunOaktonCommands(args);
```
-snippet source | anchor
+snippet source | anchor
## "Headless" Applications
diff --git a/docs/guide/diagnostics.md b/docs/guide/diagnostics.md
index ec1356475..aa1d2068e 100644
--- a/docs/guide/diagnostics.md
+++ b/docs/guide/diagnostics.md
@@ -9,7 +9,7 @@ to utilize this command line integration, you need to apply Oakton as your comma
sample `Program.cs` file:
-
+
```cs
using Oakton;
using Quickstart;
@@ -51,7 +51,7 @@ app.MapGet("/", () => Results.Redirect("/swagger"));
// your Wolverine application
return await app.RunOaktonCommands(args);
```
-snippet source | anchor
+snippet source | anchor
## Command Line Description
@@ -142,14 +142,14 @@ Probably mostly for testing projects, you can verify that all the message handle
application are in a valid state by executing this method:
-
+
```cs
public static void assert_configuration_is_valid(IHost host)
{
host.AssertWolverineConfigurationIsValid();
}
```
-snippet source | anchor
+snippet source | anchor
Note that this method will attempt to generate and compile the source code for each message type and use [Lamar's own
diff --git a/docs/guide/durability/dead-letter-storage.md b/docs/guide/durability/dead-letter-storage.md
index a60e0a996..097e1f61b 100644
--- a/docs/guide/durability/dead-letter-storage.md
+++ b/docs/guide/durability/dead-letter-storage.md
@@ -33,7 +33,23 @@ so Wolverine does have an "opt in" feature to let old messages expire and be exp
It's off by default (for backwards compatibility), but you can enable Wolverine to assign expiration times to dead letter
queue messages persisted to durable storage like this:
-snippet: sample_enabling_dead_letter_queue_expiration
+
+
+```cs
+using var host = await Host.CreateDefaultBuilder()
+ .UseWolverine(opts =>
+ {
+
+ // This is required
+ opts.Durability.DeadLetterQueueExpirationEnabled = true;
+
+ // Default is 10 days. This is the retention period
+ opts.Durability.DeadLetterQueueExpiration = 3.Days();
+
+ }).StartAsync();
+```
+snippet source | anchor
+
Note that Wolverine will use the message's `DeliverBy` value as the expiration if that exists, otherwise, Wolverine will
just add the `DeadLetterQueueExpiration` time to the current time. The actual stored messages are deleted by background
diff --git a/docs/guide/durability/idempotency.md b/docs/guide/durability/idempotency.md
index 74f4aeb1c..c417867fd 100644
--- a/docs/guide/durability/idempotency.md
+++ b/docs/guide/durability/idempotency.md
@@ -14,7 +14,7 @@ Instead of immediately deleting message storage for a successfully completed mes
that message in storage for a default of 5 minutes to protect against duplicate incoming messages. To override that setting, you have this option:
-
+
```cs
using var host = await Host.CreateDefaultBuilder()
.UseWolverine(opts =>
@@ -25,5 +25,5 @@ using var host = await Host.CreateDefaultBuilder()
opts.Durability.KeepAfterMessageHandling = 10.Minutes();
}).StartAsync();
```
-snippet source | anchor
+snippet source | anchor
diff --git a/docs/guide/durability/index.md b/docs/guide/durability/index.md
index 180d5a758..aab405fc6 100644
--- a/docs/guide/durability/index.md
+++ b/docs/guide/durability/index.md
@@ -27,7 +27,7 @@ getting lost en route.
Consider this sample message handler from Wolverine's [AppWithMiddleware sample project](https://github.com/JasperFx/wolverine/tree/main/src/Samples/Middleware):
-
+
```cs
[Transactional]
public static async Task Handle(
@@ -62,7 +62,7 @@ public static async Task Handle(
new DeliveryOptions { DeliverWithin = 5.Seconds() });
}
```
-snippet source | anchor
+snippet source | anchor
The handler code above is committing changes to an `Account` in the underlying database and potentially sending out additional messages based on the state of the `Account`.
diff --git a/docs/guide/durability/marten/ancillary-stores.md b/docs/guide/durability/marten/ancillary-stores.md
index 5dd9538f5..59d9e7c78 100644
--- a/docs/guide/durability/marten/ancillary-stores.md
+++ b/docs/guide/durability/marten/ancillary-stores.md
@@ -79,7 +79,7 @@ Now, moving to message handlers or HTTP endpoints, you will have to explicitly t
individual messages with the `[MartenStore(store type)]` attribute like this simple example below:
-
+
```cs
// This will use a Marten session from the
// IPlayerStore rather than the main IDocumentStore
@@ -93,7 +93,7 @@ public static class PlayerMessageHandler
}
}
```
-snippet source | anchor
+snippet source | anchor
::: info
diff --git a/docs/guide/durability/marten/event-sourcing.md b/docs/guide/durability/marten/event-sourcing.md
index 75985a4a1..3f1577f6a 100644
--- a/docs/guide/durability/marten/event-sourcing.md
+++ b/docs/guide/durability/marten/event-sourcing.md
@@ -23,7 +23,7 @@ And then lastly, you're going to want some resiliency and selective retry capabi
Let's just right into an example order management system. I'm going to model the order workflow with this aggregate model:
-
+
```cs
public class Item
{
@@ -67,19 +67,19 @@ public class Order
}
}
```
-snippet source | anchor
+snippet source | anchor
At a minimum, we're going to want a command handler for this command message that marks an order item as ready to ship and then evaluates whether
or not based on the current state of the `Order` aggregate whether or not the logical order is ready to be shipped out:
-
+
```cs
// OrderId refers to the identity of the Order aggregate
public record MarkItemReady(Guid OrderId, string ItemName, int Version);
```
-snippet source | anchor
+snippet source | anchor
In the code above, we're also utilizing Wolverine's [outbox messaging](/guide/durability/) support to both order and guarantee the delivery of a `ShipOrder` message when
@@ -88,7 +88,7 @@ the Marten transaction
Before getting into Wolverine middleware strategies, let's first build out an MVC controller method for the command above:
-
+
```cs
[HttpPost("/orders/itemready")]
public async Task Post(
@@ -139,7 +139,7 @@ public async Task Post(
await session.SaveChangesAsync();
}
```
-snippet source | anchor
+snippet source | anchor
Hopefully, that code is easy to understand, but there's some potentially repetitive code
@@ -152,7 +152,7 @@ pattern with Marten using the `[AggregateHandler]` middleware.
Using that middleware, we get this slimmer code:
-
+
```cs
[AggregateHandler]
public static IEnumerable Handle(MarkItemReady command, Order order)
@@ -179,7 +179,7 @@ public static IEnumerable Handle(MarkItemReady command, Order order)
}
}
```
-snippet source | anchor
+snippet source | anchor
In the case above, Wolverine is wrapping middleware around our basic command handler to
@@ -238,7 +238,7 @@ The Marten workflow command handler method signature needs to follow these rules
in the Marten `IEventStream` type (`IEventStream`). There is an example of that usage below:
-
+
```cs
[AggregateHandler]
public static void Handle(OrderEventSourcingSample.MarkItemReady command, IEventStream stream)
@@ -267,7 +267,7 @@ public static void Handle(OrderEventSourcingSample.MarkItemReady command, IEvent
}
}
```
-snippet source | anchor
+snippet source | anchor
Just as in other Wolverine [message handlers](/guide/handlers/), you can use
@@ -288,7 +288,7 @@ As for the return values from these handler methods, you can use:
Here's an alternative to the `MarkItemReady` handler that uses `Events`:
-
+
```cs
[AggregateHandler]
public static async Task<(Events, OutgoingMessages)> HandleAsync(MarkItemReady command, Order order, ISomeService service)
@@ -328,7 +328,7 @@ public static async Task<(Events, OutgoingMessages)> HandleAsync(MarkItemReady c
return (events, messages);
}
```
-snippet source | anchor
+snippet source | anchor
@@ -341,12 +341,12 @@ where the `OrderId` property is assumed to be the identity of the `Order` aggreg
by appending "Id" to the aggregate type name (it's not case sensitive if you were wondering):
-
+
```cs
// OrderId refers to the identity of the Order aggregate
public record MarkItemReady(Guid OrderId, string ItemName, int Version);
```
-snippet source | anchor
+snippet source | anchor
Or if you want to use a different member, bypass the convention, or just don't like conventional
@@ -354,7 +354,7 @@ magic, you can decorate a public member
on the command class with Marten's `[Identity]` attribute like so:
-
+
```cs
public class MarkItemReady
{
@@ -365,7 +365,7 @@ public class MarkItemReady
public string ItemName { get; init; }
}
```
-snippet source | anchor
+snippet source | anchor
## Forwarding Events
@@ -410,7 +410,7 @@ taking the `MarkItemReady` command handler we've used earlier in this guide and
produces a response of the latest aggregate:
-
+
```cs
[AggregateHandler]
public static (
@@ -448,7 +448,7 @@ public static (
return (new UpdatedAggregate(), events);
}
```
-snippet source | anchor
+snippet source | anchor
Note the usage of the `Wolverine.Marten.UpdatedAggregate` response in the handler. That type by itself is just a directive
@@ -456,7 +456,7 @@ to Wolverine to generate the necessary code to call `FetchLatest` and respond wi
us to use the command in a mediator usage like so:
-
+
```cs
public static Task update_and_get_latest(IMessageBus bus, MarkItemReady command)
{
@@ -466,7 +466,7 @@ public static Task update_and_get_latest(IMessageBus bus, MarkItemReady c
return bus.InvokeAsync(command);
}
```
-snippet source | anchor
+snippet source | anchor
]
Likewise, you can use `UpdatedAggregate` as the response body of an HTTP endpoint with Wolverine.HTTP [as shown here](/guide/http/marten.html#responding-with-the-updated-aggregate~~~~).
@@ -519,7 +519,23 @@ projections.
If you want to inject the current state of an event sourced aggregate as a parameter into
a message handler method strictly for information and don't need the heavier "aggregate handler workflow," use the `[ReadAggregate]` attribute like this:
-snippet: sample_using_ReadAggregate_in_messsage_handlers
+
+
+```cs
+public record FindAggregate(Guid Id);
+
+public static class FindLettersHandler
+{
+ // This is admittedly just some weak sauce testing support code
+ public static LetterAggregateEnvelope Handle(
+ FindAggregate command,
+ [ReadAggregate] LetterAggregate aggregate)
+
+ => new LetterAggregateEnvelope(aggregate);
+}
+```
+snippet source | anchor
+
If the aggregate doesn't exist, the HTTP request will stop with a 404 status code.
The aggregate/stream identity is found with the same rules as the `[Entity]` or `[Aggregate]` attributes:
diff --git a/docs/guide/durability/marten/operations.md b/docs/guide/durability/marten/operations.md
index 7e1f2b1bb..36427497e 100644
--- a/docs/guide/durability/marten/operations.md
+++ b/docs/guide/durability/marten/operations.md
@@ -19,7 +19,7 @@ The `Wolverine.Marten` library includes some helpers for Wolverine [side effects
Marten with the `IMartenOp` interface:
-
+
```cs
///
/// Interface for any kind of Marten related side effect
@@ -29,7 +29,7 @@ public interface IMartenOp : ISideEffect
void Execute(IDocumentSession session);
}
```
-snippet source | anchor
+snippet source | anchor
The built in side effects can all be used from the `MartenOps` static class like this HTTP endpoint example:
@@ -94,7 +94,7 @@ public static IEnumerable Handle(AppendManyNamedDocuments command)
}
}
```
-snippet source | anchor
+snippet source | anchor
Wolverine will pick up on any return type that can be cast to `IEnumerable`, so for example:
diff --git a/docs/guide/durability/marten/outbox.md b/docs/guide/durability/marten/outbox.md
index f2b1eb834..99de4784a 100644
--- a/docs/guide/durability/marten/outbox.md
+++ b/docs/guide/durability/marten/outbox.md
@@ -75,7 +75,7 @@ The Wolverine outbox is also usable from within ASP.Net Core (really any code) c
handling code would be:
-
+
```cs
public class CreateOrderController : ControllerBase
{
@@ -102,7 +102,7 @@ public class CreateOrderController : ControllerBase
}
}
```
-snippet source | anchor
+snippet source | anchor
From a Minimal API, that could be this:
diff --git a/docs/guide/durability/marten/subscriptions.md b/docs/guide/durability/marten/subscriptions.md
index 7a3ca1e0c..d7e5a5b1e 100644
--- a/docs/guide/durability/marten/subscriptions.md
+++ b/docs/guide/durability/marten/subscriptions.md
@@ -199,7 +199,7 @@ example usage where I'm using [event carried state transfer](https://martinfowle
publish batches of reference data about customers being activated or deactivated within our system:
-
+
```cs
public record CompanyActivated(string Name);
@@ -266,7 +266,7 @@ public class CompanyTransferSubscription : BatchSubscription
}
}
```
-snippet source | anchor
+snippet source | anchor
And the related code to register this subscription:
diff --git a/docs/guide/durability/marten/transactional-middleware.md b/docs/guide/durability/marten/transactional-middleware.md
index 7901323b3..980d0eb00 100644
--- a/docs/guide/durability/marten/transactional-middleware.md
+++ b/docs/guide/durability/marten/transactional-middleware.md
@@ -102,7 +102,7 @@ name ends with "Command" to use the Marten transaction middleware. You could acc
with a handler policy like this:
-
+
```cs
public class CommandsAreTransactional : IHandlerPolicy
{
@@ -116,13 +116,13 @@ public class CommandsAreTransactional : IHandlerPolicy
}
}
```
-snippet source | anchor
+snippet source | anchor
Then add the policy to your application like this:
-
+
```cs
using var host = await Host.CreateDefaultBuilder()
.UseWolverine(opts =>
@@ -131,5 +131,5 @@ using var host = await Host.CreateDefaultBuilder()
opts.Policies.Add();
}).StartAsync();
```
-snippet source | anchor
+snippet source | anchor
diff --git a/docs/guide/durability/sagas.md b/docs/guide/durability/sagas.md
index e241afe31..afad39084 100644
--- a/docs/guide/durability/sagas.md
+++ b/docs/guide/durability/sagas.md
@@ -24,7 +24,7 @@ Jumping right into an example, consider a very simple order management service t
For the moment, I’m going to ignore the underlying persistence and just focus on the Wolverine message handlers to implement the order saga workflow with this simplistic saga code:
-
+
```cs
public record StartOrder(string OrderId);
@@ -74,7 +74,7 @@ public class Order : Saga
}
```
-snippet source | anchor
+snippet source | anchor
A few explanatory notes on this code before we move on to detailed documentation:
@@ -254,7 +254,7 @@ identity. In order of precedence, Wolverine first looks for a member decorated w
`[SagaIdentity]` attribute like this:
-
+
```cs
public class ToyOnTray
{
@@ -265,7 +265,7 @@ public class ToyOnTray
[SagaIdentity] public int OrderId { get; set; }
}
```
-snippet source | anchor
+snippet source | anchor
Next, Wolverine looks for a member named "{saga type name}Id." In the case of our `Order`
@@ -443,13 +443,13 @@ Wolverine really wants you to be able to use pure functions as much as possible,
for any logical message that will be scheduled in the future like so:
-
+
```cs
// This message will always be scheduled to be delivered after
// a one minute delay
public record OrderTimeout(string Id) : TimeoutMessage(1.Minutes());
```
-snippet source | anchor
+snippet source | anchor
That `OrderTimeout` message can be published with normal cascaded messages (or by calling `IMessageBus.PublishAsync()` if you prefer)
diff --git a/docs/guide/extensions.md b/docs/guide/extensions.md
index 204b56361..596b4cae8 100644
--- a/docs/guide/extensions.md
+++ b/docs/guide/extensions.md
@@ -9,7 +9,7 @@ in the IoC container at bootstrapping time.
Wolverine supports the concept of extensions for modularizing Wolverine configuration with implementations of the `IWolverineExtension` interface:
-
+
```cs
///
/// Use to create loadable extensions to Wolverine applications
@@ -23,13 +23,13 @@ public interface IWolverineExtension
void Configure(WolverineOptions options);
}
```
-snippet source | anchor
+snippet source | anchor
Here's a sample:
-
+
```cs
public class SampleExtension : IWolverineExtension
{
@@ -44,7 +44,7 @@ public class SampleExtension : IWolverineExtension
}
}
```
-snippet source | anchor
+snippet source | anchor
Extensions can be applied programmatically against the `WolverineOptions` like this:
@@ -99,7 +99,7 @@ await using var host = await AlbaHost.For(x =>
Behind the scenes, Wolverine has a small extension like this:
-
+
```cs
internal class DisableExternalTransports : IWolverineExtension
{
@@ -109,7 +109,7 @@ internal class DisableExternalTransports : IWolverineExtension
}
}
```
-snippet source | anchor
+snippet source | anchor
And that extension is just added to the application's IoC container at test bootstrapping time like this:
@@ -179,7 +179,7 @@ There is also any option for creating Wolverine extensions that need to use asyn
the `WolverineOptions` using the `IAsyncWolverineExtension` library. A sample is shown below:
-
+
```cs
public class SampleAsyncExtension : IAsyncWolverineExtension
{
@@ -203,7 +203,7 @@ public class SampleAsyncExtension : IAsyncWolverineExtension
}
}
```
-snippet source | anchor
+snippet source | anchor
Which can be added to your application with this extension method on `IServiceCollection`:
@@ -234,7 +234,7 @@ this method in your `Program` file *after* building the `WebApplication`, but be
`MapWolverineEndpoints()` like so:
-
+
```cs
var app = builder.Build();
@@ -242,7 +242,7 @@ var app = builder.Build();
// you will need to explicitly call this *before* MapWolverineEndpoints()
await app.Services.ApplyAsyncWolverineExtensions();
```
-snippet source | anchor
+snippet source | anchor
## Wolverine Plugin Modules
diff --git a/docs/guide/handlers/batching.md b/docs/guide/handlers/batching.md
index e0d7e42c6..0554fed83 100644
--- a/docs/guide/handlers/batching.md
+++ b/docs/guide/handlers/batching.md
@@ -172,7 +172,7 @@ To teach Wolverine how to batch up our `SubTaskCompleted` messages into our cust
type:
-
+
```cs
///
/// Plugin strategy for creating custom grouping of messages
@@ -193,13 +193,13 @@ public interface IMessageBatcher
Type BatchMessageType { get; }
}
```
-snippet source | anchor
+snippet source | anchor
A custom implementation of that interface in this case would look like this:
-
+
```cs
public class SubTaskCompletedBatcher : IMessageBatcher
{
@@ -231,13 +231,13 @@ public class SubTaskCompletedBatcher : IMessageBatcher
public Type BatchMessageType => typeof(SubTaskCompletedBatch);
}
```
-snippet source | anchor
+snippet source | anchor
And of course, this doesn't work without a matching message handler for our custom message type:
-
+
```cs
public static class SubTaskCompletedBatchHandler
{
@@ -254,7 +254,7 @@ public static class SubTaskCompletedBatchHandler
}
}
```
-snippet source | anchor
+snippet source | anchor
And finally, we need to tell Wolverine about the batching and the strategy for batching the `SubTaskCompleted`
diff --git a/docs/guide/handlers/cascading.md b/docs/guide/handlers/cascading.md
index de7244903..4d5d8a2c0 100644
--- a/docs/guide/handlers/cascading.md
+++ b/docs/guide/handlers/cascading.md
@@ -17,7 +17,7 @@ maybe you need to trigger a subsequent action, or send out additional messages t
your handler class use the `IMessageContext` interface as shown in this sample:
-
+
```cs
public class NoCascadingHandler
{
@@ -36,14 +36,14 @@ public class NoCascadingHandler
}
}
```
-snippet source | anchor
+snippet source | anchor
The code above certainly works and this is consistent with most of the competing service bus tools. However, Wolverine supports the concept of _cascading messages_
that allow you to automatically send out objects returned from your handler methods without having to use `IMessageContext` as shown below:
-
+
```cs
public class CascadingHandler
{
@@ -53,7 +53,7 @@ public class CascadingHandler
}
}
```
-snippet source | anchor
+snippet source | anchor
When Wolverine executes `CascadingHandler.Consume(MyMessage)`, it "knows" that the `MyResponse` return value should be sent through the
@@ -83,7 +83,7 @@ Sometimes you'll want to explicitly send messages to specific endpoints rather t
You can still use cascading messages to an endpoint by name or by the destination `Uri` like so:
-
+
```cs
public class ManuallyRoutedResponseHandler
{
@@ -97,7 +97,7 @@ public class ManuallyRoutedResponseHandler
}
}
```
-snippet source | anchor
+snippet source | anchor
You can also add optional `DeliveryOptions` to the outgoing messages to fine tune how the message is to be published.
@@ -115,7 +115,7 @@ helps Wolverine "know" that these messages should be cascaded after the initial
The usage of this is shown below:
-
+
```cs
public static OutgoingMessages Handle(Incoming incoming)
{
@@ -141,7 +141,7 @@ public static OutgoingMessages Handle(Incoming incoming)
return messages;
}
```
-snippet source | anchor
+snippet source | anchor
Do note that the value of `OutgoingMessages` is probably greatest when being used in a tuple response from a handler that's a mix
@@ -192,7 +192,7 @@ Let's say that we have two running service bus nodes named "Sender" and "Receive
is called from the "Sender" node:
-
+
```cs
public class Requester
{
@@ -209,13 +209,13 @@ public class Requester
}
}
```
-snippet source | anchor
+snippet source | anchor
and inside Receiver we have this code:
-
+
```cs
public class CascadingHandler
{
@@ -225,7 +225,7 @@ public class CascadingHandler
}
}
```
-snippet source | anchor
+snippet source | anchor
Assuming that `MyMessage` is configured to be sent to "Receiver," the following steps take place:
@@ -244,7 +244,7 @@ different types of cascading messages based on some kind of logic, you can still
be `object` like this sample shown below:
-
+
```cs
public class ConditionalResponseHandler
{
@@ -263,7 +263,7 @@ public class ConditionalResponseHandler
}
}
```
-snippet source | anchor
+snippet source | anchor
@@ -272,7 +272,7 @@ public class ConditionalResponseHandler
You may want to raise a delayed or scheduled response. In this case you will need to return an <[linkto:documentation/integration/customizing_envelopes;title=Envelope]> for the response as shown below:
-
+
```cs
public class ScheduledResponseHandler
{
@@ -288,7 +288,7 @@ public class ScheduledResponseHandler
}
}
```
-snippet source | anchor
+snippet source | anchor
## Multiple Cascading Messages
@@ -298,7 +298,7 @@ cast to `IEnumerable`, and Wolverine will treat each element as a separa
An empty enumerable is just ignored.
-
+
```cs
public class MultipleResponseHandler
{
@@ -312,7 +312,7 @@ public class MultipleResponseHandler
}
}
```
-snippet source | anchor
+snippet source | anchor
@@ -325,7 +325,7 @@ C# tuples to better denote the cascading message types.
This handler cascading a pair of messages:
-
+
```cs
public class MultipleResponseHandler
{
@@ -339,13 +339,13 @@ public class MultipleResponseHandler
}
}
```
-snippet source | anchor
+snippet source | anchor
can be rewritten with C# 7 tuples to:
-
+
```cs
public class TupleResponseHandler
{
@@ -357,7 +357,7 @@ public class TupleResponseHandler
}
}
```
-snippet source | anchor
+snippet source | anchor
The sample above still treats both `GoNorth` and the `ScheduledResponse` as cascading messages. The Wolverine team thinks that the
diff --git a/docs/guide/handlers/discovery.md b/docs/guide/handlers/discovery.md
index f741532be..75a1183c8 100644
--- a/docs/guide/handlers/discovery.md
+++ b/docs/guide/handlers/discovery.md
@@ -128,7 +128,7 @@ In all cases, Wolverine assumes that the first argument is the incoming message.
To make that concrete, here are some valid handler method signatures:
-
+
```cs
[WolverineHandler]
public class ValidMessageHandlers
@@ -181,7 +181,7 @@ public class ValidMessageHandlers
}
}
```
-snippet source | anchor
+snippet source | anchor
The valid method names are:
@@ -214,7 +214,7 @@ You can completely turn off any automatic discovery of message handlers through
using this syntax in your `WolverineOptions`:
-
+
```cs
using var host = await Host.CreateDefaultBuilder()
.UseWolverine(opts =>
@@ -223,7 +223,7 @@ using var host = await Host.CreateDefaultBuilder()
opts.DisableConventionalDiscovery();
}).StartAsync();
```
-snippet source | anchor
+snippet source | anchor
## Replacing the Handler Discovery Rules
@@ -231,7 +231,24 @@ using var host = await Host.CreateDefaultBuilder()
You can completely replace Wolverine's handler type discovery by first disabling the conventional handler discovery,
then adding all new rules like this:
-snippet: sample_replacing_handler_discovery_rules
+
+
+```cs
+using var host = await Host.CreateDefaultBuilder()
+ .UseWolverine(opts =>
+ {
+ // Turn off Wolverine's built in handler discovery
+ opts.DisableConventionalDiscovery();
+
+ // And replace the scanning with your own special discovery:
+ opts.Discovery.CustomizeHandlerDiscovery(q =>
+ {
+ q.Includes.WithNameSuffix("Listener");
+ });
+ }).StartAsync();
+```
+snippet source | anchor
+
## Explicitly Ignoring Methods
@@ -239,7 +256,7 @@ You can force Wolverine to disregard a candidate message handler action at eithe
level by using the `[WolverineIgnore]` attribute like this:
-
+
```cs
public class NetflixHandler : IMovieSink
{
@@ -287,7 +304,7 @@ public class BlockbusterHandler
}
}
```
-snippet source | anchor
+snippet source | anchor
@@ -304,7 +321,7 @@ from those naming conventions you can either supplement the handler discovery or
At a minimum, you can disable the built in discovery, add additional type filtering criteria, or register specific handler classes with the code below:
-
+
```cs
using var host = await Host.CreateDefaultBuilder()
.UseWolverine(opts =>
@@ -327,5 +344,5 @@ using var host = await Host.CreateDefaultBuilder()
.IncludeType();
}).StartAsync();
```
-snippet source | anchor
+snippet source | anchor
diff --git a/docs/guide/handlers/error-handling.md b/docs/guide/handlers/error-handling.md
index 895e63de7..b9d7bf785 100644
--- a/docs/guide/handlers/error-handling.md
+++ b/docs/guide/handlers/error-handling.md
@@ -227,7 +227,7 @@ public class MyErrorCausingHandler
To specify global error handling rules, use the fluent interface directly on `WolverineOptions.Handlers` as shown below:
-
+
```cs
using var host = await Host.CreateDefaultBuilder()
.UseWolverine(opts =>
@@ -242,7 +242,7 @@ using var host = await Host.CreateDefaultBuilder()
.ScheduleRetry(5.Seconds());
}).StartAsync();
```
-snippet source | anchor
+snippet source | anchor
TODO -- link to chain policies, after that exists:)
@@ -251,7 +251,7 @@ Lastly, you can use chain policies to add error handling policies to a selected
a sample policy that applies an error handling policy based on `SqlException` errors for all message types from a certain namespace:
-
+
```cs
// This error policy will apply to all message types in the namespace
// 'MyApp.Messages', and add a "requeue on SqlException" to all of these
@@ -267,7 +267,7 @@ public class ErrorHandlingPolicy : IHandlerPolicy
}
}
```
-snippet source | anchor
+snippet source | anchor
## Exception Filtering
@@ -324,7 +324,7 @@ Optionally, you can implement a new type to handle this same custom logic by
subclassing the `Wolverine.ErrorHandling.UserDefinedContinuation` type like so:
-
+
```cs
public class ShippingOrderFailurePolicy : UserDefinedContinuation
{
@@ -344,7 +344,7 @@ public class ShippingOrderFailurePolicy : UserDefinedContinuation
}
}
```
-snippet source | anchor
+snippet source | anchor
and register that secondary action like this:
diff --git a/docs/guide/handlers/index.md b/docs/guide/handlers/index.md
index 744237c20..59dac70be 100644
--- a/docs/guide/handlers/index.md
+++ b/docs/guide/handlers/index.md
@@ -37,14 +37,14 @@ allow *you* to just write plain old .NET code without any framework specific art
Back to the handler code, at the point which you pass a new message into Wolverine like so:
-
+
```cs
public static async Task publish_command(IMessageBus bus)
{
await bus.PublishAsync(new MyMessage());
}
```
-snippet source | anchor
+snippet source | anchor
Between the call to `IMessageBus.PublishAsync()` and `MyMessageHandler.Handle(MyMessage)` there's a couple things
@@ -58,7 +58,7 @@ going on:
Before diving into the exact rules for message handlers, here are some valid handler methods:
-
+
```cs
[WolverineHandler]
public class ValidMessageHandlers
@@ -111,7 +111,7 @@ public class ValidMessageHandlers
}
}
```
-snippet source | anchor
+snippet source | anchor
It's also valid to use class instances with constructor arguments for your handlers:
@@ -185,7 +185,7 @@ Now though, you can flip this switch in one place to ensure that Wolverine alway
into completely separate Wolverine message handlers and message subscriptions:
-
+
```cs
using var host = Host.CreateDefaultBuilder()
.UseWolverine(opts =>
@@ -194,7 +194,7 @@ using var host = Host.CreateDefaultBuilder()
opts.MultipleHandlerBehavior = MultipleHandlerBehavior.Separated;
}).StartAsync();
```
-snippet source | anchor
+snippet source | anchor
This makes a couple changes. For example, let's say that you have these handlers for the same message type of `MyApp.Orders.OrderCreated`:
@@ -246,7 +246,7 @@ Some add ons or middleware add other possibilities as well.
Handler methods can be instance methods on handler classes if it's desirable to scope the handler object to the message:
-
+
```cs
public class ExampleHandler
{
@@ -262,7 +262,7 @@ public class ExampleHandler
}
}
```
-snippet source | anchor
+snippet source | anchor
When using instance methods, the containing handler type will be scoped to a single message and be
@@ -270,7 +270,7 @@ disposed afterward. In the case of instance methods, it's perfectly legal to use
to resolve IoC registered dependencies as shown below:
-
+
```cs
public class ServiceUsingHandler
{
@@ -290,7 +290,7 @@ public class ServiceUsingHandler
}
}
```
-snippet source | anchor
+snippet source | anchor
::: tip
@@ -301,7 +301,7 @@ improvement by avoiding the need to create and garbage collect new objects at ru
As an alternative, you can also use static methods as message handlers:
-
+
```cs
public static class ExampleHandler
{
@@ -317,7 +317,7 @@ public static class ExampleHandler
}
}
```
-snippet source | anchor
+snippet source | anchor
The handler classes can be static classes as well. This technique gets much more useful when combined with Wolverine's
@@ -332,7 +332,7 @@ arguments that will be passed into your method by Wolverine when a new message i
Below is an example action method that takes in a dependency on an `IDocumentSession` from [Marten](https://jasperfx.github.io/marten/):
-
+
```cs
public static class MethodInjectionHandler
{
@@ -345,7 +345,7 @@ public static class MethodInjectionHandler
}
}
```
-snippet source | anchor
+snippet source | anchor
So, what can be injected as an argument to your message handler?
@@ -383,7 +383,7 @@ data for both the order itself and the customer information in order to figure o
Using Wolverine's compound handler feature, that might look like this:
-
+
```cs
public static class ShipOrderHandler
{
@@ -413,7 +413,7 @@ public static class ShipOrderHandler
}
}
```
-snippet source | anchor
+snippet source | anchor
The naming conventions for what Wolverine will consider to be either a "before" or "after" method is shown below:
@@ -445,7 +445,7 @@ To access the `Envelope` for the current message being handled in your message h
argument like this:
-
+
```cs
public class EnvelopeUsingHandler
{
@@ -456,7 +456,7 @@ public class EnvelopeUsingHandler
}
}
```
-snippet source | anchor
+snippet source | anchor
@@ -467,7 +467,7 @@ or maybe to enqueue local commands within the current outbox scope, just take in
like in this example:
-
+
```cs
using Messages;
using Microsoft.Extensions.Logging;
@@ -484,8 +484,8 @@ public class PingHandler
}
}
```
-snippet source | anchor
-
+snippet source | anchor
+
```cs
public static class PingHandler
{
@@ -514,6 +514,6 @@ public static class PingHandler
}
}
```
-snippet source | anchor
+snippet source | anchor
diff --git a/docs/guide/handlers/middleware.md b/docs/guide/handlers/middleware.md
index ee8979a63..6ca261fb2 100644
--- a/docs/guide/handlers/middleware.md
+++ b/docs/guide/handlers/middleware.md
@@ -50,7 +50,7 @@ to HTTP endpoints, see [HTTP endpoint middleware](/guide/http/middleware).
As an example middleware using Wolverine's conventional approach, here's the stopwatch functionality from above:
-
+
```cs
public class StopwatchMiddleware
{
@@ -69,7 +69,7 @@ public class StopwatchMiddleware
}
}
```
-snippet source | anchor
+snippet source | anchor
and that can be added to our application at bootstrapping time like this:
@@ -174,7 +174,7 @@ Here's an example from the [custom middleware tutorial](/tutorials/middleware) t
by the incoming message and aborts the message processing if it is not found:
-
+
```cs
// This is *a* way to build middleware in Wolverine by basically just
// writing functions/methods. There's a naming convention that
@@ -207,7 +207,7 @@ public static class AccountLookupMiddleware
}
}
```
-snippet source | anchor
+snippet source | anchor
Notice that the middleware above uses a tuple as the return value so that it can both pass an `Account` entity to the inner handler and also
@@ -285,14 +285,14 @@ public static class MaybeBadThing2Handler
Let's say that some of our message types implement this interface:
-
+
```cs
public interface IAccountCommand
{
Guid AccountId { get; }
}
```
-snippet source | anchor
+snippet source | anchor
We can apply the `AccountMiddleware` from the section above to only these message types by telling Wolverine to only apply this middleware
@@ -364,7 +364,7 @@ For more advanced usage, you can drop down to the JasperFx.CodeGeneration `Frame
The first step is to create a JasperFx.CodeGeneration `Frame` class that generates that code around the inner message or HTTP handler:
-
+
```cs
public class StopwatchFrame : SyncFrame
{
@@ -410,7 +410,7 @@ public class StopwatchFrame : SyncFrame
}
}
```
-snippet source | anchor
+snippet source | anchor
@@ -420,7 +420,7 @@ To attach our `StopwatchFrame` as middleware to any route or message handler, we
`ModifyChainAttribute` class as shown below:
-
+
```cs
public class StopwatchAttribute : ModifyChainAttribute
{
@@ -430,7 +430,7 @@ public class StopwatchAttribute : ModifyChainAttribute
}
}
```
-snippet source | anchor
+snippet source | anchor
This attribute can now be placed either on a specific HTTP route endpoint method or message handler method to **only** apply to
@@ -439,7 +439,7 @@ that specific action, or it can be placed on a `Handler` or `Endpoint` class to
Here's an example:
-
+
```cs
public class ClockedEndpoint
{
@@ -450,7 +450,7 @@ public class ClockedEndpoint
}
}
```
-snippet source | anchor
+snippet source | anchor
Now, when the application is bootstrapped, this is the code that would be generated to handle the "GET /clocked" route:
@@ -499,7 +499,7 @@ Again, please go easy with this feature and try not to shoot yourself in the foo
You can register user-defined policies that apply to all chains or some subset of chains. For message handlers, implement this interface:
-
+
```cs
///
/// Use to apply your own conventions or policies to message handlers
@@ -515,13 +515,13 @@ public interface IHandlerPolicy : IWolverinePolicy
void Apply(IReadOnlyList chains, GenerationRules rules, IServiceContainer container);
}
```
-snippet source | anchor
+snippet source | anchor
Here's a simple sample that registers middleware on each handler chain:
-
+
```cs
public class WrapWithSimple : IHandlerPolicy
{
@@ -531,18 +531,18 @@ public class WrapWithSimple : IHandlerPolicy
}
}
```
-snippet source | anchor
+snippet source | anchor
Then register your custom `IHandlerPolicy` with a Wolverine application like this:
-
+
```cs
using var host = await Host.CreateDefaultBuilder()
.UseWolverine(opts => { opts.Policies.Add(); }).StartAsync();
```
-snippet source | anchor
+snippet source | anchor
## Using Configure(chain) Methods
@@ -577,7 +577,7 @@ public static void Configure(HandlerChain chain)
Here's an example of this being used from Wolverine's test suite:
-
+
```cs
public class CustomizedHandler
{
@@ -598,7 +598,7 @@ public class CustomizedHandler
}
}
```
-snippet source | anchor
+snippet source | anchor
diff --git a/docs/guide/handlers/multi-tenancy.md b/docs/guide/handlers/multi-tenancy.md
index 717f8f76c..00e186671 100644
--- a/docs/guide/handlers/multi-tenancy.md
+++ b/docs/guide/handlers/multi-tenancy.md
@@ -76,7 +76,7 @@ To that end, you can inject the `Wolverine.Persistence.TenantId` into any Wolver
to get easy access to the tenant id:
-
+
```cs
///
/// Strong typed identifier for the tenant id within a Wolverine message handler
@@ -94,7 +94,7 @@ public record TenantId(string Value)
public bool IsEmpty() => Value.IsEmpty() || Value == DefaultTenantId;
}
```
-snippet source | anchor
+snippet source | anchor
There's really nothing to it other than just pulling that type in as a parameter argument to a message handler:
diff --git a/docs/guide/handlers/persistence.md b/docs/guide/handlers/persistence.md
index 18e0844d5..2e4b5b010 100644
--- a/docs/guide/handlers/persistence.md
+++ b/docs/guide/handlers/persistence.md
@@ -112,7 +112,7 @@ or request body, you can specify the identity value source through the `EntityAt
to one of these values:
-
+
```cs
public enum ValueSource
{
@@ -132,7 +132,7 @@ public enum ValueSource
RouteValue
}
```
-snippet source | anchor
+snippet source | anchor
Some other facts to know about `[Entity]` usage:
diff --git a/docs/guide/handlers/return-values.md b/docs/guide/handlers/return-values.md
index 4769287d1..a8650cc45 100644
--- a/docs/guide/handlers/return-values.md
+++ b/docs/guide/handlers/return-values.md
@@ -54,7 +54,7 @@ For an example, let's say that you want to isolate the [side effect](https://en.
methods by returning a custom return value called `WriteFile`:
-
+
```cs
// This has to be public btw
public record WriteFile(string Path, string Contents)
@@ -65,8 +65,8 @@ public record WriteFile(string Path, string Contents)
}
}
```
-snippet source | anchor
-
+snippet source | anchor
+
```cs
// ISideEffect is a Wolverine marker interface
public class WriteFile : ISideEffect
@@ -92,7 +92,7 @@ public class WriteFile : ISideEffect
}
}
```
-snippet source | anchor
+snippet source | anchor
And now, let's teach Wolverine to call the `WriteAsync()` method on each `WriteFile` that is returned from a message handler
@@ -100,7 +100,7 @@ at runtime instead of Wolverine using the default policy of treating it as a cas
to write a custom `IChainPolicy` like so:
-
+
```cs
internal class WriteFilePolicy : IChainPolicy
{
@@ -133,17 +133,17 @@ internal class WriteFilePolicy : IChainPolicy
}
}
```
-snippet source | anchor
+snippet source | anchor
and lastly, I'll register that policy in my Wolverine application at configuration time:
-
+
```cs
using var host = await Host.CreateDefaultBuilder()
.UseWolverine(opts => { opts.Policies.Add(); }).StartAsync();
```
-snippet source | anchor
+snippet source | anchor
diff --git a/docs/guide/handlers/side-effects.md b/docs/guide/handlers/side-effects.md
index 0319ebaf2..e9f684451 100644
--- a/docs/guide/handlers/side-effects.md
+++ b/docs/guide/handlers/side-effects.md
@@ -24,7 +24,7 @@ irritating to use in tests).
First off, I'm going to create a new "side effect" type for writing a file like this:
-
+
```cs
// This has to be public btw
public record WriteFile(string Path, string Contents)
@@ -35,8 +35,8 @@ public record WriteFile(string Path, string Contents)
}
}
```
-snippet source | anchor
-
+snippet source | anchor
+
```cs
// ISideEffect is a Wolverine marker interface
public class WriteFile : ISideEffect
@@ -62,13 +62,13 @@ public class WriteFile : ISideEffect
}
}
```
-snippet source | anchor
+snippet source | anchor
And the matching message type, message handler, and a settings class for configuration:
-
+
```cs
// An options class
public class PathSettings
@@ -87,7 +87,7 @@ public class RecordTextHandler
}
}
```
-snippet source | anchor
+snippet source | anchor
At runtime, Wolverine is generating this code to handle the `RecordText` message:
diff --git a/docs/guide/handlers/sticky.md b/docs/guide/handlers/sticky.md
index 41e22dc67..5955a268e 100644
--- a/docs/guide/handlers/sticky.md
+++ b/docs/guide/handlers/sticky.md
@@ -21,11 +21,11 @@ be handled completely separately by two different handlers performing two differ
message as an input.
-
+
```cs
public class StickyMessage;
```
-snippet source | anchor
+snippet source | anchor
And we're going to handle that `StickyMessage` message separately with two different handler types:
diff --git a/docs/guide/handlers/timeout.md b/docs/guide/handlers/timeout.md
index 640ae62ce..ee2087e75 100644
--- a/docs/guide/handlers/timeout.md
+++ b/docs/guide/handlers/timeout.md
@@ -24,10 +24,10 @@ To override the message timeout on a message type by message type basis, you can
attribute as shown below:
-
+
```cs
[MessageTimeout(1)]
public async Task Handle(PotentiallySlowMessage message, CancellationToken cancellationToken)
```
-snippet source | anchor
+snippet source | anchor
diff --git a/docs/guide/http/endpoints.md b/docs/guide/http/endpoints.md
index 6266049ee..375c9b095 100644
--- a/docs/guide/http/endpoints.md
+++ b/docs/guide/http/endpoints.md
@@ -154,7 +154,7 @@ to use any return values as a the endpoint response and to return an empty respo
code. Here's an example from the tests:
-
+
```cs
[AggregateHandler]
[WolverinePost("/orders/ship"), EmptyResponse]
@@ -167,7 +167,7 @@ public static OrderShipped Ship(ShipOrder command, Order order)
return new OrderShipped();
}
```
-snippet source | anchor
+snippet source | anchor
## JSON Handling
@@ -200,9 +200,9 @@ The `IResult` mechanics are applied to the return value of any type that can be
Wolverine will execute an ASP.Net Core `IResult` object returned from an HTTP endpoint method.
-
+
```cs
-[WolverineGet("/choose/color")]
+[WolverinePost("/choose/color")]
public IResult Redirect(GoToColor request)
{
switch (request.Color)
@@ -218,7 +218,7 @@ public IResult Redirect(GoToColor request)
}
}
```
-snippet source | anchor
+snippet source | anchor
@@ -263,7 +263,7 @@ There's actually a way to customize how Wolverine handles parameters in HTTP end
To do so, you'd need to write an implementation of the `IParameterStrategy` interface from Wolverine.Http:
-
+
```cs
///
/// Apply custom handling to a Wolverine.Http endpoint/chain based on a parameter within the
@@ -275,14 +275,14 @@ public interface IParameterStrategy
bool TryMatch(HttpChain chain, IServiceContainer container, ParameterInfo parameter, out Variable? variable);
}
```
-snippet source | anchor
+snippet source | anchor
As an example, let's say that you want any parameter of type `DateTimeOffset` that's named "now" to receive the current
system time. To do that, we can write this class:
-
+
```cs
public class NowParameterStrategy : IParameterStrategy
{
@@ -301,7 +301,7 @@ public class NowParameterStrategy : IParameterStrategy
}
}
```
-snippet source | anchor
+snippet source | anchor
and register that strategy within our `MapWolverineEndpoints()` set up like so:
diff --git a/docs/guide/http/index.md b/docs/guide/http/index.md
index eee6f06ae..f015782f3 100644
--- a/docs/guide/http/index.md
+++ b/docs/guide/http/index.md
@@ -64,7 +64,7 @@ Okay, but we still need to expose a web service endpoint for this functionality.
as a "mediator" tool like so:
-
+
```cs
public class TodoController : ControllerBase
{
@@ -81,7 +81,7 @@ public class TodoController : ControllerBase
}
}
```
-snippet source | anchor
+snippet source | anchor
Or we could do the same thing with Minimal API:
diff --git a/docs/guide/http/integration.md b/docs/guide/http/integration.md
index 0d0c0386e..358fa6337 100644
--- a/docs/guide/http/integration.md
+++ b/docs/guide/http/integration.md
@@ -120,13 +120,13 @@ public async Task hello_world()
result.ReadAsText().ShouldBe("Hello.");
}
```
-snippet source | anchor
+snippet source | anchor
Moving on to the actual `Todo` problem domain, let's assume we've got a class like this:
-
+
```cs
public class Todo
{
@@ -135,7 +135,7 @@ public class Todo
public bool IsComplete { get; set; }
}
```
-snippet source | anchor
+snippet source | anchor
In a sample class called [TodoEndpoints](https://github.com/JasperFx/wolverine/blob/main/src/Samples/TodoWebService/TodoWebService/Endpoints.cs)
@@ -159,7 +159,7 @@ will shine in more complicated endpoints.
Consider this endpoint just to return the data for a single `Todo` document:
-
+
```cs
// Wolverine can infer the 200/404 status codes for you here
// so there's no code noise just to satisfy OpenAPI tooling
@@ -167,7 +167,7 @@ Consider this endpoint just to return the data for a single `Todo` document:
public static Task GetTodo(int id, IQuerySession session, CancellationToken cancellation)
=> session.LoadAsync(id, cancellation);
```
-snippet source | anchor
+snippet source | anchor
At this point it's effectively de rigueur for any web service to support [OpenAPI](https://www.openapis.org/) documentation directly
@@ -212,7 +212,7 @@ handling and response by whether or not the document actually exists. Just to sh
and also how WolverineFx.Http supports middleware, consider this more complex endpoint:
-
+
```cs
public static class UpdateTodoEndpoint
{
@@ -233,7 +233,7 @@ public static class UpdateTodoEndpoint
}
}
```
-snippet source | anchor
+snippet source | anchor
## How it Works
diff --git a/docs/guide/http/marten.md b/docs/guide/http/marten.md
index 574f5a1bf..7f639746a 100644
--- a/docs/guide/http/marten.md
+++ b/docs/guide/http/marten.md
@@ -84,7 +84,7 @@ If you want soft-deleted documents to be treated as `NULL` for a endpoint, you c
In combination with `Required = true` that means the endpoint will return 404 for missing and soft-deleted documents.
-
+
```cs
[WolverineGet("/invoices/soft-delete/{id}")]
public static Invoice GetSoftDeleted([Document(Required = true, MaybeSoftDeleted = false)] Invoice invoice)
@@ -92,7 +92,7 @@ public static Invoice GetSoftDeleted([Document(Required = true, MaybeSoftDeleted
return invoice;
}
```
-snippet source | anchor
+snippet source | anchor
@@ -242,7 +242,7 @@ public class Order
To append a single event to an event stream from an HTTP endpoint, you can use a return value like so:
-
+
```cs
[AggregateHandler]
[WolverinePost("/orders/ship"), EmptyResponse]
@@ -255,7 +255,7 @@ public static OrderShipped Ship(ShipOrder command, Order order)
return new OrderShipped();
}
```
-snippet source | anchor
+snippet source | anchor
Or potentially append multiple events using the `Events` type as a return value like this sample:
@@ -330,7 +330,14 @@ projections.
If you want to inject the current state of an event sourced aggregate as a parameter into
an HTTP endpoint method, use the `[ReadAggregate]` attribute like this:
-snippet: sample_using_ReadAggregate_in_HTTP
+
+
+```cs
+[WolverineGet("/orders/latest/{id}")]
+public static Order GetLatest(Guid id, [ReadAggregate] Order order) => order;
+```
+snippet source | anchor
+
If the aggregate doesn't exist, the HTTP request will stop with a 404 status code.
The aggregate/stream identity is found with the same rules as the `[Entity]` or `[Aggregate]` attributes:
diff --git a/docs/guide/http/messaging.md b/docs/guide/http/messaging.md
index d0f499ffd..318a84596 100644
--- a/docs/guide/http/messaging.md
+++ b/docs/guide/http/messaging.md
@@ -10,7 +10,7 @@ So there's absolutely nothing stopping you from just using `IMessageBus` as an i
dependency to a Wolverine HTTP endpoint method to publish messages like this sample:
-
+
```cs
// This would have an empty response and a 204 status code
[WolverinePost("/spawn3")]
@@ -20,7 +20,7 @@ public static async ValueTask SendViaMessageBus(IMessageBus bus)
await bus.PublishAsync(new HttpMessage2("bar"));
}
```
-snippet source | anchor
+snippet source | anchor
But of course there's some other alternatives to directly using `IMessageBus` by utilizing Wolverine's [cascading messages](/guide/handlers/cascading)
@@ -39,7 +39,7 @@ to be immediately published to Wolverine without any need for additional Wolveri
Note that this mechanism will return an empty body with a status code of 202 to denote future processing.
-
+
```cs
var builder = WebApplication.CreateBuilder();
@@ -61,13 +61,13 @@ app.MapWolverineEndpoints(opts =>
// and the rest of your application configuration and bootstrapping
```
-snippet source | anchor
+snippet source | anchor
On the other hand, the `PublishAsync()` method will send a message if there is a known subscriber and ignore the message if there is no subscriber (as explained in [sending or publishing Messages](/guide/messaging/message-bus#sending-or-publishing-messages)):
-
+
```cs
var builder = WebApplication.CreateBuilder();
@@ -89,7 +89,7 @@ app.MapWolverineEndpoints(opts =>
// and the rest of your application configuration and bootstrapping
```
-snippet source | anchor
+snippet source | anchor
Middleware policies from Wolverine.Http are applicable to these endpoints, so for example, it's feasible to use
@@ -104,7 +104,7 @@ that this collection of objects is meant to be cascaded messages that are publis
Here's an example:
-
+
```cs
// This would have a string response and a 200 status code
[WolverinePost("/spawn")]
@@ -121,14 +121,14 @@ public static (string, OutgoingMessages) Post(SpawnInput input)
return ("got it", messages);
}
```
-snippet source | anchor
+snippet source | anchor
Otherwise, if you want to make it clearer from the signature of your HTTP handler method what messages are cascaded
and there's no variance in the type of messages published, you can use additional tuple return values like this:
-
+
```cs
// This would have an empty response and a 204 status code
[EmptyResponse]
@@ -138,5 +138,5 @@ public static (HttpMessage1, HttpMessage2) Post()
return new(new HttpMessage1("foo"), new HttpMessage2("bar"));
}
```
-snippet source | anchor
+snippet source | anchor
diff --git a/docs/guide/http/metadata.md b/docs/guide/http/metadata.md
index d6534b362..e1c355392 100644
--- a/docs/guide/http/metadata.md
+++ b/docs/guide/http/metadata.md
@@ -68,7 +68,7 @@ for finer grained control. Here's a sample from the Wolverine testing code that
determine the OpenAPI operation id:
-
+
```cs
// This class is NOT distributed in any kind of Nuget today, but feel very free
// to copy this code into your own as it is at least tested through Wolverine's
@@ -84,7 +84,7 @@ public class WolverineOperationFilter : IOperationFilter // IOperationFilter is
}
}
```
-snippet source | anchor
+snippet source | anchor
And that would be registered with Swashbuckle inside of your `Program.Main()` method like so:
@@ -135,7 +135,7 @@ an HTTP endpoint, you can have your response type implement the `IHttpAware` int
consider the `CreationResponse` type in Wolverine:
-
+
```cs
///
/// Base class for resource types that denote some kind of resource being created
@@ -161,7 +161,7 @@ public record CreationResponse([StringSyntax("Route")]string Url) : IHttpAware
public static CreationResponse For(T value, string url) => new CreationResponse(url, value);
}
```
-snippet source | anchor
+snippet source | anchor
Any endpoint that returns `CreationResponse` or a sub class will automatically expose a status code of `201` for successful
diff --git a/docs/guide/http/middleware.md b/docs/guide/http/middleware.md
index 991b13a1f..1b6700a9c 100644
--- a/docs/guide/http/middleware.md
+++ b/docs/guide/http/middleware.md
@@ -59,7 +59,7 @@ object is anything else, Wolverine will execute that `IResult` and stop processi
For a little more complex example, here's part of the Fluent Validation middleware for Wolverine.Http:
-
+
```cs
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static async Task ExecuteOne(IValidator validator, IProblemDetailSource source, T message)
@@ -79,7 +79,7 @@ public static async Task ExecuteOne(IValidator validator, IProble
return WolverineContinue.Result();
}
```
-snippet source | anchor
+snippet source | anchor
Likewise, you can also just return a `null` from middleware for `IResult` and Wolverine will interpret that as
@@ -161,7 +161,7 @@ this middleware is applied to any endpoint that also uses Wolverine message publ
from the `HttpContext` to subsequent Wolverine messages published during the request:
-
+
```cs
public static class RequestIdMiddleware
{
@@ -177,13 +177,13 @@ public static class RequestIdMiddleware
}
}
```
-snippet source | anchor
+snippet source | anchor
And a matching `IHttpPolicy` to apply that middleware to any HTTP endpoint where there is a dependency on Wolverine's `IMessageContext` or `IMessageBus`:
-
+
```cs
internal class RequestIdPolicy : IHttpPolicy
{
@@ -201,7 +201,7 @@ internal class RequestIdPolicy : IHttpPolicy
}
}
```
-snippet source | anchor
+snippet source | anchor
Lastly, this particular policy is included by default, but if it wasn't, this is the code to apply it explicitly:
diff --git a/docs/guide/http/multi-tenancy.md b/docs/guide/http/multi-tenancy.md
index 00a89ad86..7068dd74e 100644
--- a/docs/guide/http/multi-tenancy.md
+++ b/docs/guide/http/multi-tenancy.md
@@ -260,7 +260,7 @@ of multi-tenancy, so you can completely opt out of all tenant id detection and a
`[NotTenanted]` attribute as shown here in the tests:
-
+
```cs
// Mark this endpoint as not using any kind of multi-tenancy
[WolverineGet("/nottenanted"), NotTenanted]
@@ -269,7 +269,7 @@ public static string NoTenantNoProblem()
return "hey";
}
```
-snippet source | anchor
+snippet source | anchor
If the above usage completely disabled all tenant id detection or validation, in the case of an endpoint that *might* be
@@ -299,7 +299,7 @@ parameters. Wolverine still has you covered by allowing you to create custom imp
interface:
-
+
```cs
///
/// Used to create new strategies to detect the tenant id from an HttpContext
@@ -315,13 +315,13 @@ public interface ITenantDetection
public ValueTask DetectTenant(HttpContext context);
}
```
-snippet source | anchor
+snippet source | anchor
As any example, the route argument detection implementation looks like this:
-
+
```cs
internal class ArgumentDetection : ITenantDetection, ISynchronousTenantDetection
{
@@ -350,7 +350,7 @@ internal class ArgumentDetection : ITenantDetection, ISynchronousTenantDetection
}
}
```
-snippet source | anchor
+snippet source | anchor
::: tip
@@ -462,7 +462,7 @@ Using the `WolverineFx.Http.Marten` Nuget, there's a helper to replace Marten's
with a multi-tenanted version like this:
-
+
```cs
builder.Services.AddMartenTenancyDetection(tenantId =>
{
@@ -470,8 +470,8 @@ builder.Services.AddMartenTenancyDetection(tenantId =>
tenantId.DefaultIs("default-tenant");
});
```
-snippet source | anchor
-
+snippet source | anchor
+
```cs
builder.Services.AddMartenTenancyDetection(tenantId =>
{
@@ -482,6 +482,6 @@ builder.Services.AddMartenTenancyDetection(tenantId =>
session.CorrelationId = c.TraceIdentifier;
});
```
-snippet source | anchor
+snippet source | anchor
diff --git a/docs/guide/http/policies.md b/docs/guide/http/policies.md
index c7405ae65..01840657e 100644
--- a/docs/guide/http/policies.md
+++ b/docs/guide/http/policies.md
@@ -4,7 +4,7 @@ Custom policies can be created for HTTP endpoints through either creating your o
shown below:
-
+
```cs
///
/// Use to apply your own conventions or policies to HTTP endpoint handlers
@@ -20,7 +20,7 @@ public interface IHttpPolicy
void Apply(IReadOnlyList chains, GenerationRules rules, IServiceContainer container);
}
```
-snippet source | anchor
+snippet source | anchor
And then adding a policy to the `WolverineHttpOptions` like this code from the Fluent Validation extension for HTTP:
@@ -105,7 +105,7 @@ app.MapWolverineEndpoints(opts =>
Wolverine has an additional type of policy that deals with how an endpoints primary result is handled.
-
+
```cs
///
/// Use to apply custom handling to the primary result of an HTTP endpoint handler
@@ -120,7 +120,7 @@ public interface IResourceWriterPolicy
bool TryApply(HttpChain chain);
}
```
-snippet source | anchor
+snippet source | anchor
Only one of these so called resource writer policies can apply to each endpoint and there are a couple of built in policies already.
diff --git a/docs/guide/http/problemdetails.md b/docs/guide/http/problemdetails.md
index b839abe13..29fe6a8e4 100644
--- a/docs/guide/http/problemdetails.md
+++ b/docs/guide/http/problemdetails.md
@@ -7,7 +7,7 @@ off, explicit validation for certain endpoints.
Consider this contrived sample endpoint with explicit validation being done in a "Before" middleware method:
-
+
```cs
public class ProblemDetailsUsageEndpoint
{
@@ -35,7 +35,7 @@ public class ProblemDetailsUsageEndpoint
public record NumberMessage(int Number);
```
-snippet source | anchor
+snippet source | anchor
Wolverine.Http now (as of 1.2.0) has a convention that sees a return value of `ProblemDetails` and looks at that as a
diff --git a/docs/guide/http/security.md b/docs/guide/http/security.md
index be0fd01dd..849bced11 100644
--- a/docs/guide/http/security.md
+++ b/docs/guide/http/security.md
@@ -16,7 +16,7 @@ app.MapWolverineEndpoints(opts =>
or more selectively, the code above is just syntactical sugar for:
-
+
```cs
///
/// Equivalent of calling RequireAuthorization() on all wolverine endpoints
@@ -26,5 +26,5 @@ public void RequireAuthorizeOnAll()
ConfigureEndpoints(e => e.RequireAuthorization());
}
```
-snippet source | anchor
+snippet source | anchor
diff --git a/docs/guide/logging.md b/docs/guide/logging.md
index 6d5688c57..3127570c0 100644
--- a/docs/guide/logging.md
+++ b/docs/guide/logging.md
@@ -43,7 +43,7 @@ you don't want logging for that particular message type, but do for all other me
level for only that specific message type like so:
-
+
```cs
public class CustomizedHandler
{
@@ -64,7 +64,7 @@ public class CustomizedHandler
}
}
```
-snippet source | anchor
+snippet source | anchor
Methods on message handler types with the signature:
@@ -84,7 +84,7 @@ way to do that is to use the `[WolverineLogging]` attribute on either the handle
below:
-
+
```cs
public class QuietMessage;
@@ -100,7 +100,7 @@ public class QuietMessageHandler
}
}
```
-snippet source | anchor
+snippet source | anchor
@@ -352,7 +352,7 @@ public const string SendingResumed = "wolverine.sending.resumed";
///
public const string TooManySenderFailures = "TooManySenderFailures";
```
-snippet source | anchor
+snippet source | anchor
## Message Correlation
diff --git a/docs/guide/messages.md b/docs/guide/messages.md
index c9f72ad29..c97fd4a6b 100644
--- a/docs/guide/messages.md
+++ b/docs/guide/messages.md
@@ -19,7 +19,7 @@ to Newtonsoft.JSON or to use higher performance [MemoryPack](/guide/messages.htm
Let's say that you have a basic message structure like this:
-
+
```cs
public class PersonBorn
{
@@ -33,7 +33,7 @@ public class PersonBorn
public int Year { get; set; }
}
```
-snippet source | anchor
+snippet source | anchor
By default, Wolverine will identify this type by just using the .NET full name like so:
@@ -114,12 +114,12 @@ The marker types shown above may be helpful in transitioning an existing codebas
You can optionally use an attribute to mark a type as a message:
-
+
```cs
[WolverineMessage]
public record CloseIssue(Guid Id);
```
-snippet source | anchor
+snippet source | anchor
Or lastly, make up your own criteria to find and mark message types within your system as shown below:
@@ -143,7 +143,7 @@ Going back to the original `PersonBorn` message class in previous sections, let'
create a new version of that message that is no longer structurally equivalent to the original message:
-
+
```cs
[MessageIdentity("person-born", Version = 2)]
public class PersonBornV2
@@ -153,7 +153,7 @@ public class PersonBornV2
public DateTime Birthday { get; set; }
}
```
-snippet source | anchor
+snippet source | anchor
The `[Version("V2")]` attribute usage tells Wolverine that this class is "V2" for the `message-type` = "person-born."
@@ -176,14 +176,14 @@ And to instead opt into using System.Text.Json with different defaults -- which
increased risk of serialization failures -- use this syntax where `opts` is a `WolverineOptions` object:
-
+
```cs
opts.UseSystemTextJsonForSerialization(stj =>
{
stj.UnknownTypeHandling = JsonUnknownTypeHandling.JsonNode;
});
```
-snippet source | anchor
+snippet source | anchor
When using Newtonsoft.Json, the default configuration is:
@@ -203,7 +203,7 @@ return new JsonSerializerSettings
To customize the Newtonsoft.Json serialization, use this option:
-
+
```cs
using var host = await Host.CreateDefaultBuilder()
.UseWolverine(opts =>
@@ -214,7 +214,7 @@ using var host = await Host.CreateDefaultBuilder()
});
}).StartAsync();
```
-snippet source | anchor
+snippet source | anchor
### MessagePack Serialization
@@ -305,7 +305,7 @@ using var host = await Host.CreateDefaultBuilder()
If you make breaking changes to an incoming message in a later version, you can simply handle both versions of that message separately:
-
+
```cs
public class PersonCreatedHandler
{
@@ -320,14 +320,14 @@ public class PersonCreatedHandler
}
}
```
-snippet source | anchor
+snippet source | anchor
Or you could use a custom `IMessageDeserializer` to read incoming messages from V1 into the new V2 message type, or you can take advantage of message forwarding
so you only need to handle one message type using the `IForwardsTo` interface as shown below:
-
+
```cs
public class PersonBorn : IForwardsTo
{
@@ -348,13 +348,13 @@ public class PersonBorn : IForwardsTo
}
}
```
-snippet source | anchor
+snippet source | anchor
Which forwards to the current message type:
-
+
```cs
[MessageIdentity("person-born", Version = 2)]
public class PersonBornV2
@@ -364,7 +364,7 @@ public class PersonBornV2
public DateTime Birthday { get; set; }
}
```
-snippet source | anchor
+snippet source | anchor
Using this strategy, other systems could still send your system the original `application/vnd.person-born.v1+json` formatted
diff --git a/docs/guide/messaging/expiration.md b/docs/guide/messaging/expiration.md
index 4675d516e..ca232362b 100644
--- a/docs/guide/messaging/expiration.md
+++ b/docs/guide/messaging/expiration.md
@@ -20,7 +20,7 @@ public DateTimeOffset? DeliverBy
set => _deliverBy = value?.ToUniversalTime();
}
```
-snippet source | anchor
+snippet source | anchor
At runtime, Wolverine will:
diff --git a/docs/guide/messaging/listeners.md b/docs/guide/messaging/listeners.md
index 92d90a8de..5335674e2 100644
--- a/docs/guide/messaging/listeners.md
+++ b/docs/guide/messaging/listeners.md
@@ -139,7 +139,7 @@ In the case where you need messages from a single endpoint to be processed in st
you have the `ListenWithStrictOrdering()` option:
-
+
```cs
var host = await Host.CreateDefaultBuilder().UseWolverine(opts =>
{
@@ -153,7 +153,7 @@ var host = await Host.CreateDefaultBuilder().UseWolverine(opts =>
.ListenWithStrictOrdering();
}).StartAsync();
```
-snippet source | anchor
+snippet source | anchor
This option does a couple things:
diff --git a/docs/guide/messaging/message-bus.md b/docs/guide/messaging/message-bus.md
index 7a745774c..1cf4d1798 100644
--- a/docs/guide/messaging/message-bus.md
+++ b/docs/guide/messaging/message-bus.md
@@ -141,7 +141,7 @@ You can explicitly override this behavior on a handler by handler basis with the
as shown below:
-
+
```cs
public class CreateItemCommandHandler
{
@@ -162,7 +162,7 @@ public class CreateItemCommandHandler
}
}
```
-snippet source | anchor
+snippet source | anchor
## Disabling Remote Request/Reply
@@ -185,7 +185,7 @@ using var host = Host.CreateDefaultBuilder()
opts.EnableRemoteInvocation = false;
}).StartAsync();
```
-snippet source | anchor
+snippet source | anchor
## Sending or Publishing Messages
@@ -279,7 +279,7 @@ actually have a couple different syntactical options. First, if you're directly
can schedule a message with a delay using this extension method:
-
+
```cs
public async Task schedule_send(IMessageContext context, Guid issueId)
{
@@ -298,13 +298,13 @@ public async Task schedule_send(IMessageContext context, Guid issueId)
});
}
```
-snippet source | anchor
+snippet source | anchor
Or using an absolute time, with this overload of the extension method:
-
+
```cs
public async Task schedule_send_at_5_tomorrow_afternoon(IMessageContext context, Guid issueId)
{
@@ -321,7 +321,7 @@ public async Task schedule_send_at_5_tomorrow_afternoon(IMessageContext context,
await context.ScheduleAsync(timeout, time);
}
```
-snippet source | anchor
+snippet source | anchor
Now, Wolverine tries really hard to enable you to use [pure functions](https://en.wikipedia.org/wiki/Pure_function) for as many message handlers as possible, so
@@ -354,13 +354,13 @@ Lastly, there's a special base class called `TimeoutMessage` that your message t
directly to the message itself for easy usage as a cascaded message. Here's an example message type:
-
+
```cs
// This message will always be scheduled to be delivered after
// a one minute delay
public record OrderTimeout(string Id) : TimeoutMessage(1.Minutes());
```
-snippet source | anchor
+snippet source | anchor
Which is used within this sample saga implementation:
@@ -387,7 +387,7 @@ public static (Order, OrderTimeout) Start(StartOrder order, ILogger logge
TODO -- more text here. NEW PAGE???
-
+
```cs
public static async Task SendMessagesWithDeliveryOptions(IMessageBus bus)
{
@@ -405,7 +405,7 @@ public static async Task SendMessagesWithDeliveryOptions(IMessageBus bus)
.WithHeader("tenant", "one"));
}
```
-snippet source | anchor
+snippet source | anchor
diff --git a/docs/guide/messaging/subscriptions.md b/docs/guide/messaging/subscriptions.md
index 7614466fa..b08c6108e 100644
--- a/docs/guide/messaging/subscriptions.md
+++ b/docs/guide/messaging/subscriptions.md
@@ -44,7 +44,7 @@ of the Wolverine configuration.
Programmatically, this code shows how to "look" into the configured Wolverine subscriptions for a message type:
-
+
```cs
public static void PreviewRouting(IHost host)
{
@@ -72,7 +72,7 @@ public static void PreviewRouting(IHost host)
}
}
```
-snippet source | anchor
+snippet source | anchor
First, you can always use the [command line support](/guide/command-line) to preview Wolverine's known message types by using:
@@ -95,7 +95,7 @@ preview functionality by "telling" Wolverine what your outgoing message types ar
To route messages to specific endpoints, we can apply static message routing rules by using a routing rule as shown below:
-
+
```cs
using var host = Host.CreateDefaultBuilder()
.UseWolverine(opts =>
@@ -144,7 +144,7 @@ using var host = Host.CreateDefaultBuilder()
opts.PublishAllMessages().ToPort(3333);
}).StartAsync();
```
-snippet source | anchor
+snippet source | anchor
Do note that doing the message type filtering by namespace will also include child namespaces. In
@@ -215,7 +215,7 @@ for a message type that "knows" how to create the Wolverine `Envelope` for a sin
outgoing message to a single subscribing endpoint:
-
+
```cs
///
/// Contains all the rules for where and how an outgoing message
@@ -227,7 +227,7 @@ public interface IMessageRoute
WolverineRuntime runtime, string? topicName);
}
```
-snippet source | anchor
+snippet source | anchor
This type "knows" about any endpoint or model sending customizations like delivery expiration
@@ -291,7 +291,7 @@ Let's say you want to use a completely different conventional routing topology t
of the box. You can do that by creating your own implementation of this interface:
-
+
```cs
///
/// Plugin for doing any kind of conventional message routing
@@ -314,7 +314,7 @@ public interface IMessageRoutingConvention
IEnumerable DiscoverSenders(Type messageType, IWolverineRuntime runtime);
}
```
-snippet source | anchor
+snippet source | anchor
As a concrete example, the Wolverine team received [this request](https://github.com/JasperFx/wolverine/issues/1130) to conventionally route messages based on
@@ -323,7 +323,7 @@ That's not something that Wolverine supports out of the box, but you could build
convention like this:
-
+
```cs
public class RouteKeyConvention : IMessageRoutingConvention
{
@@ -357,13 +357,13 @@ public class RouteKeyConvention : IMessageRoutingConvention
}
}
```
-snippet source | anchor
+snippet source | anchor
And register it to your Wolverine application like so:
-
+
```cs
var builder = Host.CreateApplicationBuilder();
var rabbitConnectionString = builder
@@ -384,7 +384,7 @@ builder.UseWolverine(opts =>
// actually start the app...
```
-snippet source | anchor
+snippet source | anchor
diff --git a/docs/guide/messaging/transports/local.md b/docs/guide/messaging/transports/local.md
index b769a8ee3..c7037abc2 100644
--- a/docs/guide/messaging/transports/local.md
+++ b/docs/guide/messaging/transports/local.md
@@ -31,7 +31,7 @@ Some things to know about the local queues:
If you want to enqueue a message locally to a specific worker queue, you can use this syntax:
-
+
```cs
public ValueTask EnqueueToQueue(IMessageContext bus)
{
@@ -48,7 +48,7 @@ public ValueTask EnqueueToQueue(IMessageContext bus)
return bus.EndpointFor("highpriority").SendAsync(@event);
}
```
-snippet source | anchor
+snippet source | anchor
## Scheduling Local Execution
@@ -100,7 +100,7 @@ public class ImportanceMessage;
Otherwise, you can take advantage of Wolverine's message routing rules like this:
-
+
```cs
using var host = await Host.CreateDefaultBuilder()
.UseWolverine(opts =>
@@ -111,7 +111,7 @@ using var host = await Host.CreateDefaultBuilder()
.ToLocalQueue("important");
}).StartAsync();
```
-snippet source | anchor
+snippet source | anchor
The routing rules and/or `[LocalQueue]` routing is also honored for cascading messages, meaning that any message that is handled inside a Wolverine system could publish cascading messages to the local worker queues.
@@ -219,7 +219,7 @@ the Wolverine naming conventions. To get back to leaning more on the type system
interface that can be implemented on any handler type to configure the local queue where that handler would run:
-
+
```cs
///
/// Helps mark a handler to configure the local queue that its messages
@@ -231,7 +231,7 @@ public interface IConfigureLocalQueue
static abstract void Configure(LocalQueueConfiguration configuration);
}
```
-snippet source | anchor
+snippet source | anchor
::: tip
@@ -242,7 +242,7 @@ handler type itself cannot be static. Just a .NET quirk.
To use this, just implement that interface on any message handler type:
-
+
```cs
public class MultipleMessage1Handler : IConfigureLocalQueue
{
@@ -259,7 +259,7 @@ public class MultipleMessage1Handler : IConfigureLocalQueue
}
}
```
-snippet source | anchor
+snippet source | anchor
## Durable Local Messages
@@ -269,7 +269,7 @@ The local worker queues can optionally be designated as "durable," meaning that
Here is an example of configuring a local queue to be durable:
-
+
```cs
using var host = await Host.CreateDefaultBuilder()
.UseWolverine(opts =>
@@ -282,7 +282,7 @@ using var host = await Host.CreateDefaultBuilder()
.UseDurableInbox();
}).StartAsync();
```
-snippet source | anchor
+snippet source | anchor
@@ -294,7 +294,7 @@ See [Durable Inbox and Outbox Messaging](/guide/durability/) for more informatio
The queues are built on top of the TPL Dataflow library, so it's pretty easy to configure parallelization (how many concurrent messages could be handled by a queue). Here's an example of how to establish this:
-
+
```cs
using var host = await Host.CreateDefaultBuilder()
.UseWolverine(opts =>
@@ -328,7 +328,7 @@ using var host = await Host.CreateDefaultBuilder()
opts.LocalQueue("four").UseDurableInbox();
}).StartAsync();
```
-snippet source | anchor
+snippet source | anchor
@@ -342,7 +342,7 @@ locally enqueued messages or scheduled messages that may have initially failed.
In the sample Wolverine configuration shown below:
-
+
```cs
using var host = await Host.CreateDefaultBuilder()
.UseWolverine(opts =>
@@ -353,7 +353,7 @@ using var host = await Host.CreateDefaultBuilder()
.ToLocalQueue("important");
}).StartAsync();
```
-snippet source | anchor
+snippet source | anchor
Calling `IMessageBus.SendAsync(new Message2())` would publish the message to the local "important" queue.
diff --git a/docs/guide/messaging/transports/mqtt.md b/docs/guide/messaging/transports/mqtt.md
index d15b9d4bf..6f41679d3 100644
--- a/docs/guide/messaging/transports/mqtt.md
+++ b/docs/guide/messaging/transports/mqtt.md
@@ -127,21 +127,12 @@ would be derived from either Wolverine's [message type name](/guide/messages.htm
or by using the `[Topic("topic name")]` attribute as shown below:
-
+
```cs
[Topic("one")]
public class TopicMessage1;
```
-snippet source | anchor
-
-```cs
-[Topic("color.blue")]
-public class FirstMessage
-{
- public Guid Id { get; set; } = Guid.NewGuid();
-}
-```
-snippet source | anchor
+snippet source | anchor
## Publishing by Topic Rules
@@ -263,7 +254,7 @@ For more complex interoperability, you can implement the `IMqttEnvelopeMapper` i
incoming and outgoing MQTT messages and the Wolverine `Envelope` structure. Here's an example:
-
+
```cs
public class MyMqttEnvelopeMapper : IMqttEnvelopeMapper
{
@@ -294,7 +285,7 @@ public class MyMqttEnvelopeMapper : IMqttEnvelopeMapper
}
}
```
-snippet source | anchor
+snippet source | anchor
And apply that to an MQTT topic like so:
diff --git a/docs/guide/messaging/transports/rabbitmq/conventional-routing.md b/docs/guide/messaging/transports/rabbitmq/conventional-routing.md
index 769a58dd0..773063b89 100644
--- a/docs/guide/messaging/transports/rabbitmq/conventional-routing.md
+++ b/docs/guide/messaging/transports/rabbitmq/conventional-routing.md
@@ -20,7 +20,7 @@ using var host = await Host.CreateDefaultBuilder()
.UseConventionalRouting();
}).StartAsync();
```
-snippet source | anchor
+snippet source | anchor
With the defaults from above, for each message that the application can handle
@@ -73,7 +73,7 @@ using var host = await Host.CreateDefaultBuilder()
});
}).StartAsync();
```
-snippet source | anchor
+snippet source | anchor
## Adjusting Routing Conventions
@@ -122,7 +122,7 @@ var receiver = WolverineHost.For(opts =>
});
});
```
-snippet source | anchor
+snippet source | anchor
diff --git a/docs/guide/messaging/transports/rabbitmq/deadletterqueues.md b/docs/guide/messaging/transports/rabbitmq/deadletterqueues.md
index e45bcf6b6..4b6fc6488 100644
--- a/docs/guide/messaging/transports/rabbitmq/deadletterqueues.md
+++ b/docs/guide/messaging/transports/rabbitmq/deadletterqueues.md
@@ -31,7 +31,7 @@ using var host = await Host.CreateDefaultBuilder()
.DeadLetterQueueing(new DeadLetterQueue("incoming-errors"));
}).StartAsync();
```
-snippet source | anchor
+snippet source | anchor
::: warning
@@ -66,7 +66,7 @@ using var host = await Host.CreateDefaultBuilder()
.DeadLetterQueueing(new DeadLetterQueue("incoming-errors", DeadLetterQueueMode.InteropFriendly));
}).StartAsync();
```
-snippet source | anchor
+snippet source | anchor
And lastly, if you don't particularly want to have any Rabbit MQ dead letter queues and you quite like the [database backed
@@ -93,7 +93,7 @@ using var host = await Host.CreateDefaultBuilder()
opts.ListenToRabbitQueue("incoming").DisableDeadLetterQueueing();
}).StartAsync();
```
-snippet source | anchor
+snippet source | anchor
diff --git a/docs/guide/messaging/transports/rabbitmq/index.md b/docs/guide/messaging/transports/rabbitmq/index.md
index 4879bf902..18278c777 100644
--- a/docs/guide/messaging/transports/rabbitmq/index.md
+++ b/docs/guide/messaging/transports/rabbitmq/index.md
@@ -79,7 +79,7 @@ using var host = await Host.CreateDefaultBuilder()
});
}).StartAsync();
```
-snippet source | anchor
+snippet source | anchor
To only send Rabbit MQ messages, but never receive them:
@@ -108,7 +108,7 @@ using var host = await Host.CreateDefaultBuilder()
});
}).StartAsync();
```
-snippet source | anchor
+snippet source | anchor
@@ -134,7 +134,7 @@ using var host = await Host.CreateDefaultBuilder()
.EnableWolverineControlQueues();
}).StartAsync();
```
-snippet source | anchor
+snippet source | anchor
@@ -170,7 +170,7 @@ using var host = await Host.CreateDefaultBuilder()
});
}).StartAsync();
```
-snippet source | anchor
+snippet source | anchor
Of course, doing so means that you will not be able to do request/reply through Rabbit MQ with your Wolverine application.
diff --git a/docs/guide/messaging/transports/rabbitmq/interoperability.md b/docs/guide/messaging/transports/rabbitmq/interoperability.md
index 6e0580743..1a16c36cf 100644
--- a/docs/guide/messaging/transports/rabbitmq/interoperability.md
+++ b/docs/guide/messaging/transports/rabbitmq/interoperability.md
@@ -39,7 +39,7 @@ builder.UseWolverine(opts =>
using var host = builder.Build();
await host.StartAsync();
```
-snippet source | anchor
+snippet source | anchor
With this setting, there is **no other required headers** for Wolverine to process incoming messages. However, Wolverine will be
@@ -135,7 +135,7 @@ builder.UseWolverine(opts =>
using var host = builder.Build();
await host.StartAsync();
```
-snippet source | anchor
+snippet source | anchor
@@ -155,7 +155,7 @@ At this point, the interoperability is only built and tested for the [Rabbit MQ
Here's a sample:
-
+
```cs
Wolverine = await Host.CreateDefaultBuilder().UseWolverine(opts =>
{
@@ -181,7 +181,7 @@ Wolverine = await Host.CreateDefaultBuilder().UseWolverine(opts =>
opts.Policies.RegisterInteropMessageAssembly(typeof(IInterfaceMessage).Assembly);
}).StartAsync();
```
-snippet source | anchor
+snippet source | anchor
## Interoperability with Mass Transit
@@ -198,7 +198,7 @@ with MassTransit, and don't try to use that endpoint for Wolverine to Wolverine
The configuration to do this is shown below:
-
+
```cs
Wolverine = await Host.CreateDefaultBuilder().UseWolverine(opts =>
{
@@ -226,5 +226,5 @@ Wolverine = await Host.CreateDefaultBuilder().UseWolverine(opts =>
.DefaultIncomingMessage().UseForReplies();
}).StartAsync();
```
-snippet source | anchor
+snippet source | anchor
diff --git a/docs/guide/messaging/transports/rabbitmq/listening.md b/docs/guide/messaging/transports/rabbitmq/listening.md
index 5d2636a9f..560ed08a9 100644
--- a/docs/guide/messaging/transports/rabbitmq/listening.md
+++ b/docs/guide/messaging/transports/rabbitmq/listening.md
@@ -38,7 +38,7 @@ using var host = await Host.CreateDefaultBuilder()
});
}).StartAsync();
```
-snippet source | anchor
+snippet source | anchor
To optimize and tune the message processing, you may want to read more about the [Rabbit MQ prefetch count and prefetch
@@ -80,5 +80,5 @@ using var host = await Host.CreateDefaultBuilder()
});
}).StartAsync();
```
-snippet source | anchor
+snippet source | anchor
diff --git a/docs/guide/messaging/transports/rabbitmq/multiple-brokers.md b/docs/guide/messaging/transports/rabbitmq/multiple-brokers.md
index e589155d7..1a4562d62 100644
--- a/docs/guide/messaging/transports/rabbitmq/multiple-brokers.md
+++ b/docs/guide/messaging/transports/rabbitmq/multiple-brokers.md
@@ -39,7 +39,7 @@ builder.UseWolverine(opts =>
opts.PublishAllMessages().ToRabbitTopicsOnNamedBroker(external, "topics");
});
```
-snippet source | anchor
+snippet source | anchor
The `Uri` values for endpoints to the additional broker follows the same rules as the normal usage of the Rabbit MQ
diff --git a/docs/guide/messaging/transports/rabbitmq/object-management.md b/docs/guide/messaging/transports/rabbitmq/object-management.md
index 162917b2c..2a3157cd9 100644
--- a/docs/guide/messaging/transports/rabbitmq/object-management.md
+++ b/docs/guide/messaging/transports/rabbitmq/object-management.md
@@ -30,7 +30,7 @@ using var host = await Host.CreateDefaultBuilder()
opts.PublishAllMessages().ToRabbitExchange("exchange1");
}).StartAsync();
```
-snippet source | anchor
+snippet source | anchor
At development time -- or occasionally in production systems -- you may want to have the messaging
@@ -47,7 +47,7 @@ using var host = await Host.CreateDefaultBuilder()
.AutoPurgeOnStartup();
}).StartAsync();
```
-snippet source | anchor
+snippet source | anchor
Or you can be more selective and only have certain queues of volatile messages purged
@@ -64,7 +64,7 @@ using var host = await Host.CreateDefaultBuilder()
.DeclareQueue("queue2", q => q.PurgeOnStartup = true);
}).StartAsync();
```
-snippet source | anchor
+snippet source | anchor
Wolverine's Rabbit MQ integration also supports the [Oakton stateful resource](https://jasperfx.github.io/oakton/guide/host/resources.html) model,
@@ -172,7 +172,36 @@ are largely not impacted otherwise.
Here are your options for configuring one or many queues as opting into being a "Quorum Queue" or a "Stream":
-snippet: sample_configuring_quorum_or_streams_in_rabbit_MQ
+
+
+```cs
+var builder = Host.CreateApplicationBuilder();
+builder.UseWolverine(opts =>
+{
+ opts
+ .UseRabbitMq(builder.Configuration.GetConnectionString("rabbit"))
+
+ // You can configure the queue type for declaration with this
+ // usage as well
+ .DeclareQueue("stream", q => q.QueueType = QueueType.stream)
+
+ // Use quorum queues by default as a policy
+ .UseQuorumQueues()
+
+ // Or instead use streams
+ .UseStreamsAsQueues();
+
+ opts.ListenToRabbitQueue("quorum1")
+ // Override the queue type in declarations for a
+ // single queue, and the explicit configuration will win
+ // out over any policy or convention
+ .QueueType(QueueType.quorum);
+
+
+});
+```
+snippet source | anchor
+
There are just a few things to know:
@@ -186,7 +215,7 @@ you can quickly access and make additions to the Rabbit MQ integration with your
like so:
-
+
```cs
public class MyModuleExtension : IWolverineExtension
{
@@ -201,6 +230,6 @@ public class MyModuleExtension : IWolverineExtension
}
}
```
-snippet source | anchor
+snippet source | anchor
diff --git a/docs/guide/messaging/transports/rabbitmq/publishing.md b/docs/guide/messaging/transports/rabbitmq/publishing.md
index c73fc2f67..b6352655b 100644
--- a/docs/guide/messaging/transports/rabbitmq/publishing.md
+++ b/docs/guide/messaging/transports/rabbitmq/publishing.md
@@ -23,7 +23,7 @@ using var host = await Host.CreateDefaultBuilder()
opts.PublishAllMessages().ToRabbitQueue("special", queue => { queue.IsExclusive = true; });
}).StartAsync();
```
-snippet source | anchor
+snippet source | anchor
## Publish to an Exchange
@@ -55,7 +55,7 @@ using var host = await Host.CreateDefaultBuilder()
});
}).StartAsync();
```
-snippet source | anchor
+snippet source | anchor
## Publish to a Routing Key
@@ -84,6 +84,6 @@ using var host = await Host.CreateDefaultBuilder()
opts.PublishAllMessages().ToRabbitExchange("exchange1");
}).StartAsync();
```
-snippet source | anchor
+snippet source | anchor
diff --git a/docs/guide/messaging/transports/rabbitmq/topics.md b/docs/guide/messaging/transports/rabbitmq/topics.md
index a5fd63d45..8b1904d0e 100644
--- a/docs/guide/messaging/transports/rabbitmq/topics.md
+++ b/docs/guide/messaging/transports/rabbitmq/topics.md
@@ -23,7 +23,7 @@ using var host = await Host.CreateDefaultBuilder()
opts.ListenToRabbitQueue("");
}).StartAsync();
```
-snippet source | anchor
+snippet source | anchor
While we're specifying the exchange name ("topics-exchange"), we did nothing to specify the topic
@@ -35,7 +35,7 @@ name. With this set up, when you publish a message in this application like so:
var publisher = host.MessageBus();
await publisher.SendAsync(new Message1());
```
-snippet source | anchor
+snippet source | anchor
You will be sending that message to the "topics-exchange" with a topic name derived from
@@ -48,19 +48,13 @@ on a message type like so:
```cs
-[Topic("one")]
-public class TopicMessage1;
-```
-snippet source | anchor
-
-```cs
[Topic("color.blue")]
public class FirstMessage
{
public Guid Id { get; set; } = Guid.NewGuid();
}
```
-snippet source | anchor
+snippet source | anchor
Of course, you can always explicitly send a message to a specific topic with this syntax:
@@ -70,7 +64,7 @@ Of course, you can always explicitly send a message to a specific topic with thi
```cs
await publisher.BroadcastToTopicAsync("color.*", new Message1());
```
-snippet source | anchor
+snippet source | anchor
Note two things about the code above:
@@ -117,7 +111,7 @@ public interface ITenantMessage
string TenantId { get; }
}
```
-snippet source | anchor
+snippet source | anchor
Let's say that any message that implements that interface, we want published to the
@@ -144,5 +138,5 @@ builder.UseWolverine(opts =>
using var host = builder.Build();
await host.StartAsync();
```
-snippet source | anchor
+snippet source | anchor
diff --git a/docs/guide/messaging/transports/tcp.md b/docs/guide/messaging/transports/tcp.md
index 6ce1f7dbc..56a3df8c3 100644
--- a/docs/guide/messaging/transports/tcp.md
+++ b/docs/guide/messaging/transports/tcp.md
@@ -13,7 +13,7 @@ You can listen to messages from as many ports as you like, but be aware of port
To listen for messages with the TCP transport, use the `ListenAtPort()` extension method shown below:
-
+
```cs
public static IHost CreateHostBuilder()
{
@@ -41,7 +41,7 @@ public static IHost CreateHostBuilder()
return builder.Build();
}
```
-snippet source | anchor
+snippet source | anchor
Likewise, to publish via TCP, use the `ToPort()` extension method to publish to another port on the same
@@ -79,7 +79,7 @@ var answer = bus.EndpointFor("One")
or use `ToServerAndPort()` to send messages to a port on another machine:
-
+
```cs
using var host = Host.CreateDefaultBuilder()
.UseWolverine(opts =>
@@ -128,7 +128,7 @@ using var host = Host.CreateDefaultBuilder()
opts.PublishAllMessages().ToPort(3333);
}).StartAsync();
```
-snippet source | anchor
+snippet source | anchor
diff --git a/docs/guide/migration.md b/docs/guide/migration.md
index 293e563f3..9175dffdc 100644
--- a/docs/guide/migration.md
+++ b/docs/guide/migration.md
@@ -134,7 +134,7 @@ You can selectively override this behavior and tell Wolverine to publish the res
by using the new 3.0 `[AlwaysPublishResponse]` attribute like this:
-
+
```cs
public class CreateItemCommandHandler
{
@@ -155,5 +155,5 @@ public class CreateItemCommandHandler
}
}
```
-snippet source | anchor
+snippet source | anchor
diff --git a/docs/guide/runtime.md b/docs/guide/runtime.md
index 4b2771323..82f3156ce 100644
--- a/docs/guide/runtime.md
+++ b/docs/guide/runtime.md
@@ -8,7 +8,7 @@ everything is just a message.
The two key parts of a Wolverine application are messages:
-
+
```cs
// A "command" message
public record DebitAccount(long AccountId, decimal Amount);
@@ -16,13 +16,13 @@ public record DebitAccount(long AccountId, decimal Amount);
// An "event" message
public record AccountOverdrawn(long AccountId);
```
-snippet source | anchor
+snippet source | anchor
And the message handling code for the messages, which in Wolverine's case just means a function or method that accepts the message type as its first argument like so:
-
+
```cs
public static class DebitAccountHandler
{
@@ -32,7 +32,7 @@ public static class DebitAccountHandler
}
}
```
-snippet source | anchor
+snippet source | anchor
## Invoking a Message Inline
@@ -239,7 +239,7 @@ The stateful, running "agents" are exposed through an `IAgent`
interface like so:
-
+
```cs
///
/// Models a constantly running background process within a Wolverine
@@ -262,13 +262,13 @@ public enum AgentStatus
Paused
}
```
-snippet source | anchor
+snippet source | anchor
With related groups of agents built and assigned by IoC-registered implementations of this interface:
-
+
```cs
///
/// Pluggable model for managing the assignment and execution of stateful, "sticky"
@@ -310,7 +310,7 @@ public interface IAgentFamily
ValueTask EvaluateAssignmentsAsync(AssignmentGrid assignments);
}
```
-snippet source | anchor
+snippet source | anchor
Built in examples of the agent and agent family are:
diff --git a/docs/guide/testing.md b/docs/guide/testing.md
index 8d16b4491..ef22f8077 100644
--- a/docs/guide/testing.md
+++ b/docs/guide/testing.md
@@ -19,7 +19,7 @@ For an example, let's look at this message handler for applying a debit to a ban
will use [cascading messages](/guide/handlers/cascading) to raise a variable number of additional messages:
-
+
```cs
[Transactional]
public static IEnumerable Handle(
@@ -51,7 +51,7 @@ public static IEnumerable Handle(
yield return new AccountUpdated(account.Id, account.Balance);
}
```
-snippet source | anchor
+snippet source | anchor
The testing extensions can be seen in action by the following test:
@@ -118,7 +118,7 @@ Here's a different version of the message handler from the previous section, but
directly:
-
+
```cs
[Transactional]
public static async Task Handle(
@@ -153,7 +153,7 @@ public static async Task Handle(
new DeliveryOptions { DeliverWithin = 5.Seconds() });
}
```
-snippet source | anchor
+snippet source | anchor
To test this handler, we can use `TestMessageContext` as a stand in to just record
diff --git a/docs/tutorials/cqrs-with-marten.md b/docs/tutorials/cqrs-with-marten.md
index a78f310d3..63c047296 100644
--- a/docs/tutorials/cqrs-with-marten.md
+++ b/docs/tutorials/cqrs-with-marten.md
@@ -96,7 +96,7 @@ and will probably evolve through subsequent user stories. We're starting from an
so we're going to skip ahead to some of our initial event types:
-
+
```cs
public class Incident
{
@@ -129,7 +129,7 @@ public class Incident
public bool ShouldDelete(Archived @event) => true;
}
```
-snippet source | anchor
+snippet source | anchor
::: info
@@ -182,7 +182,7 @@ our code, so here's the first cut at the HTTP endpoint that will log a new incid
for the incident in one file:
-
+
```cs
public record LogIncident(
Guid CustomerId,
@@ -207,7 +207,7 @@ public static class LogIncidentEndpoint
}
}
```
-snippet source | anchor
+snippet source | anchor
And maybe there's a few details to unpack. It might help to [see the code](/guide/codegen) that Wolverine generates for this HTTP
@@ -338,20 +338,20 @@ overrides so that you are mostly using the application **as it is actually confi
As a little tip, I've added this bit of marker code to the very bottom of our `Program` file:
-
+
```cs
// Adding this just makes it easier to bootstrap your
// application in a test harness project. Only a convenience
public partial class Program{}
```
-snippet source | anchor
+snippet source | anchor
Having that above, I'll switch to the test harness project and create a shared fixture to bootstrap
the `IHost` for the application throughout the integration tests:
-
+
```cs
public class AppFixture : IAsyncLifetime
{
@@ -384,14 +384,14 @@ public class AppFixture : IAsyncLifetime
}
}
```
-snippet source | anchor
+snippet source | anchor
And I like to add a base class for integration tests with some convenience methods that have
been useful here and there:
-
+
```cs
[CollectionDefinition("integration")]
public class IntegrationCollection : ICollectionFixture;
@@ -454,7 +454,7 @@ public abstract class IntegrationContext : IAsyncLifetime
}
}
```
-snippet source | anchor
+snippet source | anchor
With all of that in place (and if you're using Docker for your infrastructure, a quick `docker compose up -d` command),
@@ -507,7 +507,7 @@ allows you to express most command handlers that target Marten event sourcing as
On to the code:
-
+
```cs
public record CategoriseIncident(
IncidentCategory Category,
@@ -548,7 +548,7 @@ public static class CategoriseIncidentEndpoint
}
}
```
-snippet source | anchor
+snippet source | anchor
In this case, I'm sourcing the `Incident` value using the `incidentId` route argument as
diff --git a/docs/tutorials/from-mediatr.md b/docs/tutorials/from-mediatr.md
index dadefb122..0e595d3dc 100644
--- a/docs/tutorials/from-mediatr.md
+++ b/docs/tutorials/from-mediatr.md
@@ -159,7 +159,7 @@ avoid the really nasty kind of Exception stack traces you get from many other mi
Let's say that you have a Wolverine.HTTP endpoint like so:
-
+
```cs
public record CreateCustomer
(
@@ -188,7 +188,7 @@ public static class CreateCustomerEndpoint
}
}
```
-snippet source | anchor
+snippet source | anchor
In the application bootstrapping, I've added this option:
diff --git a/docs/tutorials/getting-started.md b/docs/tutorials/getting-started.md
index 53b5b302c..a39e702d2 100644
--- a/docs/tutorials/getting-started.md
+++ b/docs/tutorials/getting-started.md
@@ -52,17 +52,17 @@ public record CreateIssue(Guid OriginatorId, string Title, string Description);
and
-
+
```cs
public record AssignIssue(Guid IssueId, Guid AssigneeId);
```
-snippet source | anchor
+snippet source | anchor
Let's jump right into the `Program.cs` file of our new web service:
-
+
```cs
using Oakton;
using Quickstart;
@@ -104,7 +104,7 @@ app.MapGet("/", () => Results.Redirect("/swagger"));
// your Wolverine application
return await app.RunOaktonCommands(args);
```
-snippet source | anchor
+snippet source | anchor
::: tip
@@ -126,7 +126,7 @@ inline. In a simplistic form, here is the entire handler file for the `CreateIss
command:
-
+
```cs
namespace Quickstart;
@@ -160,7 +160,7 @@ public class CreateIssueHandler
}
}
```
-snippet source | anchor
+snippet source | anchor
Hopefully that code is simple enough, but let's talk what you do not see in this code or
@@ -194,7 +194,7 @@ the initial web service call.
The `IssueHandled` event message will be handled by this code:
-
+
```cs
public static class IssueCreatedHandler
{
@@ -218,7 +218,7 @@ public static class IssueCreatedHandler
}
}
```
-snippet source | anchor
+snippet source | anchor
Now, you'll notice that Wolverine is happy to allow you to use static methods as
diff --git a/docs/tutorials/mediator.md b/docs/tutorials/mediator.md
index 7f60c6174..bdc9cc7d1 100644
--- a/docs/tutorials/mediator.md
+++ b/docs/tutorials/mediator.md
@@ -71,7 +71,7 @@ From there, we'll slightly modify the `Program` file generated by the `webapi` t
into Wolverine's [extended command line support](/guide/command-line):
-
+
```cs
var builder = WebApplication.CreateBuilder(args);
@@ -98,7 +98,7 @@ builder.Services.AddDbContext(
// use this DbContext type
optionsLifetime: ServiceLifetime.Singleton);
```
-snippet source | anchor
+snippet source | anchor
Now, let's add a Wolverine message handler that will:
@@ -110,7 +110,7 @@ Now, let's add a Wolverine message handler that will:
Using idiomatic Wolverine, that handler looks like this:
-
+
```cs
public class ItemHandler
{
@@ -145,7 +145,7 @@ public class ItemHandler
}
}
```
-snippet source | anchor
+snippet source | anchor
**Note**, as long as this handler class is public and in the main application assembly, Wolverine is going
@@ -155,11 +155,11 @@ to find it and wire it up inside its execution pipeline. There's no explicit cod
Now, moving up to the API layer, we can add a new HTTP endpoint to delegate to Wolverine as a mediator with:
-
+
```cs
app.MapPost("/items/create", (CreateItemCommand cmd, IMessageBus bus) => bus.InvokeAsync(cmd));
```
-snippet source | anchor
+snippet source | anchor
There isn't much to this code -- and that's the entire point! When Wolverine registers itself into
@@ -184,7 +184,7 @@ As a contrast, here's what the same functionality looks like if you write all th
explicitly in a controller action:
-
+
```cs
// This controller does all the transactional work and business
// logic all by itself
@@ -226,7 +226,7 @@ public class DoItAllMyselfItemController : ControllerBase
}
}
```
-snippet source | anchor
+snippet source | anchor
So one, there's just more going on in the `/items/create` HTTP endpoint defined above because you're needing to do a little bit of
@@ -246,11 +246,11 @@ output of the message handler to the HTTP response body (and assume we'll use JS
example code simpler):
-
+
```cs
app.MapPost("/items/create2", (CreateItemCommand cmd, IMessageBus bus) => bus.InvokeAsync(cmd));
```
-snippet source | anchor
+snippet source | anchor
Using the `IMessageBus.Invoke(message)` overload, the returned `ItemCreated` response
diff --git a/docs/tutorials/middleware.md b/docs/tutorials/middleware.md
index 2a8291ee3..7f5c459e0 100644
--- a/docs/tutorials/middleware.md
+++ b/docs/tutorials/middleware.md
@@ -32,31 +32,31 @@ Using Wolverine's [conventional middleware approach](/guide/handlers/middleware.
command message types that reference an `Account` like so:
-
+
```cs
public interface IAccountCommand
{
Guid AccountId { get; }
}
```
-snippet source | anchor
+snippet source | anchor
So a command message might look like this:
-
+
```cs
public record CreditAccount(Guid AccountId, decimal Amount) : IAccountCommand;
```
-snippet source | anchor
+snippet source | anchor
Skipping ahead a little bit, if we had a handler for the `CreditAccount` command type above that was counting on some kind of middleware to just "push" the matching
`Account` data in, the handler might just be this:
-
+
```cs
public static class CreditAccountHandler
{
@@ -78,7 +78,7 @@ public static class CreditAccountHandler
}
}
```
-snippet source | anchor
+snippet source | anchor
You'll notice at this point that the message handler is synchronous because it's no longer doing any calls to the database. Besides removing some repetitive code, this appproach
@@ -88,7 +88,7 @@ Next, let's build the actual middleware that will attempt to load an `Account` m
or be aborted. Here's sample code to do exactly that:
-
+
```cs
// This is *a* way to build middleware in Wolverine by basically just
// writing functions/methods. There's a naming convention that
@@ -121,7 +121,7 @@ public static class AccountLookupMiddleware
}
}
```
-snippet source | anchor
+snippet source | anchor
Now, some notes about the code above:
diff --git a/docs/tutorials/ping-pong.md b/docs/tutorials/ping-pong.md
index 37e664631..75171fd9e 100644
--- a/docs/tutorials/ping-pong.md
+++ b/docs/tutorials/ping-pong.md
@@ -7,7 +7,7 @@ To show off some of the messaging, let's just build [a very simple "Ping/Pong" e
First off, I'm going to build out a very small shared library just to hold the messages we're going to exchange:
-
+
```cs
public class Ping
{
@@ -19,13 +19,13 @@ public class Pong
public int Number { get; set; }
}
```
-snippet source | anchor
+snippet source | anchor
And next, I'll start a small *Pinger* service with the `dotnet new worker` template. There's just three pieces of code, starting with the boostrapping code:
-
+
```cs
using Messages;
using Oakton;
@@ -50,13 +50,13 @@ return await Host.CreateDefaultBuilder(args)
})
.RunOaktonCommands(args);
```
-snippet source | anchor
+snippet source | anchor
and the `Worker` class that's just going to publish a new `Ping` message once a second:
-
+
```cs
using Messages;
using Wolverine;
@@ -88,13 +88,13 @@ public class Worker : BackgroundService
}
}
```
-snippet source | anchor
+snippet source | anchor
and lastly a message handler for any `Pong` messages coming back from the `Ponger` we'll build next:
-
+
```cs
using Messages;
@@ -108,14 +108,14 @@ public class PongHandler
}
}
```
-snippet source | anchor
+snippet source | anchor
Okay then, next let's move on to building the `Ponger` application. This time I'll use `dotnet new console` to start the new
project, then add references to our *Messages* library and Wolverine itself. For the bootstrapping, add this code:
-
+
```cs
using Microsoft.Extensions.Hosting;
using Oakton;
@@ -130,14 +130,14 @@ return await Host.CreateDefaultBuilder(args)
})
.RunOaktonCommands(args);
```
-snippet source | anchor
+snippet source | anchor
And a message handler for the `Ping` messages that will turn right around and shoot a `Pong` response right back
to the original sender:
-
+
```cs
using Messages;
using Microsoft.Extensions.Logging;
@@ -154,8 +154,8 @@ public class PingHandler
}
}
```
-snippet source | anchor
-
+snippet source | anchor
+
```cs
public static class PingHandler
{
@@ -184,7 +184,7 @@ public static class PingHandler
}
}
```
-snippet source | anchor
+snippet source | anchor
If I start up first the *Ponger* service, then the *Pinger* service, I'll see console output like this from *Pinger*:
diff --git a/docs/tutorials/railway-programming.md b/docs/tutorials/railway-programming.md
index ac4c92f03..c77cc7b9a 100644
--- a/docs/tutorials/railway-programming.md
+++ b/docs/tutorials/railway-programming.md
@@ -75,7 +75,7 @@ You have more specialized ways of doing that in HTTP endpoints by using the `Pro
processing like this example that uses a `Validate()` method to potentially stop processing with a descriptive 400 and error message:
-
+
```cs
public record CategoriseIncident(
IncidentCategory Category,
@@ -116,7 +116,7 @@ public static class CategoriseIncidentEndpoint
}
}
```
-snippet source | anchor
+snippet source | anchor
The value `WolverineContinue.NoProblems` tells Wolverine that everything is good, full speed ahead. Anything else will write the `ProblemDetails`