diff --git a/src/Http/Wolverine.Http.Tests/Internal/Generated/WolverineHandlers/GET_maybe.cs b/src/Http/Wolverine.Http.Tests/Internal/Generated/WolverineHandlers/GET_maybe.cs
new file mode 100644
index 000000000..64e1dd6cf
--- /dev/null
+++ b/src/Http/Wolverine.Http.Tests/Internal/Generated/WolverineHandlers/GET_maybe.cs
@@ -0,0 +1,52 @@
+//
+#pragma warning disable
+using Microsoft.AspNetCore.Routing;
+using System;
+using System.Linq;
+using Wolverine.Http;
+using Wolverine.Runtime;
+
+namespace Internal.Generated.WolverineHandlers
+{
+ // START: GET_maybe
+ [global::System.CodeDom.Compiler.GeneratedCode("JasperFx", "1.0.0")]
+ public sealed class GET_maybe : Wolverine.Http.HttpHandler
+ {
+ private readonly Wolverine.Http.WolverineHttpOptions _wolverineHttpOptions;
+ private readonly Wolverine.Runtime.IWolverineRuntime _wolverineRuntime;
+
+ public GET_maybe(Wolverine.Http.WolverineHttpOptions wolverineHttpOptions, Wolverine.Runtime.IWolverineRuntime wolverineRuntime) : base(wolverineHttpOptions)
+ {
+ _wolverineHttpOptions = wolverineHttpOptions;
+ _wolverineRuntime = wolverineRuntime;
+ }
+
+
+
+ public override async System.Threading.Tasks.Task Handle(Microsoft.AspNetCore.Http.HttpContext httpContext)
+ {
+
+ // Tenant Id detection
+ // 1. Tenant Id is query string value 'tenant'
+ var tenantId = await TryDetectTenantId(httpContext);
+ var messageContext = new Wolverine.Runtime.MessageContext(_wolverineRuntime);
+ messageContext.TenantId = tenantId;
+ Wolverine.Http.Runtime.RequestIdMiddleware.Apply(httpContext, messageContext);
+
+ // The actual HTTP request handler execution
+ var result_of_MaybeTenanted = Wolverine.Http.Tests.MultiTenancy.TenantedEndpoints.MaybeTenanted(messageContext);
+
+ await WriteString(httpContext, result_of_MaybeTenanted);
+
+ // Have to flush outgoing messages just in case Marten did nothing because of https://github.com/JasperFx/wolverine/issues/536
+ await messageContext.FlushOutgoingMessagesAsync().ConfigureAwait(false);
+
+ }
+
+ }
+
+ // END: GET_maybe
+
+
+}
+
diff --git a/src/Http/Wolverine.Http.Tests/Internal/Generated/WolverineHandlers/GET_nottenanted.cs b/src/Http/Wolverine.Http.Tests/Internal/Generated/WolverineHandlers/GET_nottenanted.cs
new file mode 100644
index 000000000..c7b555104
--- /dev/null
+++ b/src/Http/Wolverine.Http.Tests/Internal/Generated/WolverineHandlers/GET_nottenanted.cs
@@ -0,0 +1,38 @@
+//
+#pragma warning disable
+using Microsoft.AspNetCore.Routing;
+using System;
+using System.Linq;
+using Wolverine.Http;
+
+namespace Internal.Generated.WolverineHandlers
+{
+ // START: GET_nottenanted
+ [global::System.CodeDom.Compiler.GeneratedCode("JasperFx", "1.0.0")]
+ public sealed class GET_nottenanted : Wolverine.Http.HttpHandler
+ {
+ private readonly Wolverine.Http.WolverineHttpOptions _wolverineHttpOptions;
+
+ public GET_nottenanted(Wolverine.Http.WolverineHttpOptions wolverineHttpOptions) : base(wolverineHttpOptions)
+ {
+ _wolverineHttpOptions = wolverineHttpOptions;
+ }
+
+
+
+ public override async System.Threading.Tasks.Task Handle(Microsoft.AspNetCore.Http.HttpContext httpContext)
+ {
+
+ // The actual HTTP request handler execution
+ var result_of_NoTenantNoProblem = Wolverine.Http.Tests.MultiTenancy.TenantedEndpoints.NoTenantNoProblem();
+
+ await WriteString(httpContext, result_of_NoTenantNoProblem);
+ }
+
+ }
+
+ // END: GET_nottenanted
+
+
+}
+
diff --git a/src/Http/Wolverine.Http.Tests/Internal/Generated/WolverineHandlers/GET_tenant.cs b/src/Http/Wolverine.Http.Tests/Internal/Generated/WolverineHandlers/GET_tenant.cs
new file mode 100644
index 000000000..a7bdf1eff
--- /dev/null
+++ b/src/Http/Wolverine.Http.Tests/Internal/Generated/WolverineHandlers/GET_tenant.cs
@@ -0,0 +1,53 @@
+//
+#pragma warning disable
+using Microsoft.AspNetCore.Routing;
+using System;
+using System.Linq;
+using Wolverine.Http;
+using Wolverine.Runtime;
+
+namespace Internal.Generated.WolverineHandlers
+{
+ // START: GET_tenant
+ [global::System.CodeDom.Compiler.GeneratedCode("JasperFx", "1.0.0")]
+ public sealed class GET_tenant : Wolverine.Http.HttpHandler
+ {
+ private readonly Wolverine.Http.WolverineHttpOptions _wolverineHttpOptions;
+ private readonly Wolverine.Runtime.IWolverineRuntime _wolverineRuntime;
+
+ public GET_tenant(Wolverine.Http.WolverineHttpOptions wolverineHttpOptions, Wolverine.Runtime.IWolverineRuntime wolverineRuntime) : base(wolverineHttpOptions)
+ {
+ _wolverineHttpOptions = wolverineHttpOptions;
+ _wolverineRuntime = wolverineRuntime;
+ }
+
+
+
+ public override async System.Threading.Tasks.Task Handle(Microsoft.AspNetCore.Http.HttpContext httpContext)
+ {
+
+ // Tenant Id detection
+ // 1. Tenant Id is request header 'tenant'
+ var tenantId = await TryDetectTenantId(httpContext);
+ var tenantIdentifier = new JasperFx.MultiTenancy.TenantId(tenantId);
+ var messageContext = new Wolverine.Runtime.MessageContext(_wolverineRuntime);
+ messageContext.TenantId = tenantId;
+ Wolverine.Http.Runtime.RequestIdMiddleware.Apply(httpContext, messageContext);
+
+ // The actual HTTP request handler execution
+ var result_of_GetTenantIdFromWhatever = Wolverine.Http.Tests.MultiTenancy.TenantedEndpoints.GetTenantIdFromWhatever(messageContext, httpContext, tenantIdentifier);
+
+ await WriteString(httpContext, result_of_GetTenantIdFromWhatever);
+
+ // Have to flush outgoing messages just in case Marten did nothing because of https://github.com/JasperFx/wolverine/issues/536
+ await messageContext.FlushOutgoingMessagesAsync().ConfigureAwait(false);
+
+ }
+
+ }
+
+ // END: GET_tenant
+
+
+}
+
diff --git a/src/Http/Wolverine.Http.Tests/Internal/Generated/WolverineHandlers/GET_tenant_both_tenant.cs b/src/Http/Wolverine.Http.Tests/Internal/Generated/WolverineHandlers/GET_tenant_both_tenant.cs
new file mode 100644
index 000000000..36f756b92
--- /dev/null
+++ b/src/Http/Wolverine.Http.Tests/Internal/Generated/WolverineHandlers/GET_tenant_both_tenant.cs
@@ -0,0 +1,59 @@
+//
+#pragma warning disable
+using Microsoft.AspNetCore.Routing;
+using System;
+using System.Linq;
+using Wolverine.Http;
+using Wolverine.Runtime;
+
+namespace Internal.Generated.WolverineHandlers
+{
+ // START: GET_tenant_both_tenant
+ [global::System.CodeDom.Compiler.GeneratedCode("JasperFx", "1.0.0")]
+ public sealed class GET_tenant_both_tenant : Wolverine.Http.HttpHandler
+ {
+ private readonly Wolverine.Http.WolverineHttpOptions _wolverineHttpOptions;
+ private readonly Wolverine.Runtime.IWolverineRuntime _wolverineRuntime;
+
+ public GET_tenant_both_tenant(Wolverine.Http.WolverineHttpOptions wolverineHttpOptions, Wolverine.Runtime.IWolverineRuntime wolverineRuntime) : base(wolverineHttpOptions)
+ {
+ _wolverineHttpOptions = wolverineHttpOptions;
+ _wolverineRuntime = wolverineRuntime;
+ }
+
+
+
+ public override async System.Threading.Tasks.Task Handle(Microsoft.AspNetCore.Http.HttpContext httpContext)
+ {
+
+ // Tenant Id detection
+ // 1. Tenant Id is route argument named 'tenant'
+ var tenantId = await TryDetectTenantId(httpContext);
+ if (string.IsNullOrEmpty(tenantId))
+ {
+ await WriteTenantIdNotFound(httpContext);
+ return;
+ }
+
+ var tenantIdentifier = new JasperFx.MultiTenancy.TenantId(tenantId);
+ var messageContext = new Wolverine.Runtime.MessageContext(_wolverineRuntime);
+ messageContext.TenantId = tenantId;
+ Wolverine.Http.Runtime.RequestIdMiddleware.Apply(httpContext, messageContext);
+
+ // The actual HTTP request handler execution
+ var result_of_GetTenantWithArgs1 = Wolverine.Http.Tests.MultiTenancy.TenantedEndpoints.GetTenantWithArgs1(messageContext, messageContext, tenantIdentifier);
+
+ await WriteString(httpContext, result_of_GetTenantWithArgs1);
+
+ // Have to flush outgoing messages just in case Marten did nothing because of https://github.com/JasperFx/wolverine/issues/536
+ await messageContext.FlushOutgoingMessagesAsync().ConfigureAwait(false);
+
+ }
+
+ }
+
+ // END: GET_tenant_both_tenant
+
+
+}
+
diff --git a/src/Http/Wolverine.Http.Tests/Internal/Generated/WolverineHandlers/GET_tenant_bus_tenant.cs b/src/Http/Wolverine.Http.Tests/Internal/Generated/WolverineHandlers/GET_tenant_bus_tenant.cs
new file mode 100644
index 000000000..8b4b1e6d9
--- /dev/null
+++ b/src/Http/Wolverine.Http.Tests/Internal/Generated/WolverineHandlers/GET_tenant_bus_tenant.cs
@@ -0,0 +1,59 @@
+//
+#pragma warning disable
+using Microsoft.AspNetCore.Routing;
+using System;
+using System.Linq;
+using Wolverine.Http;
+using Wolverine.Runtime;
+
+namespace Internal.Generated.WolverineHandlers
+{
+ // START: GET_tenant_bus_tenant
+ [global::System.CodeDom.Compiler.GeneratedCode("JasperFx", "1.0.0")]
+ public sealed class GET_tenant_bus_tenant : Wolverine.Http.HttpHandler
+ {
+ private readonly Wolverine.Http.WolverineHttpOptions _wolverineHttpOptions;
+ private readonly Wolverine.Runtime.IWolverineRuntime _wolverineRuntime;
+
+ public GET_tenant_bus_tenant(Wolverine.Http.WolverineHttpOptions wolverineHttpOptions, Wolverine.Runtime.IWolverineRuntime wolverineRuntime) : base(wolverineHttpOptions)
+ {
+ _wolverineHttpOptions = wolverineHttpOptions;
+ _wolverineRuntime = wolverineRuntime;
+ }
+
+
+
+ public override async System.Threading.Tasks.Task Handle(Microsoft.AspNetCore.Http.HttpContext httpContext)
+ {
+
+ // Tenant Id detection
+ // 1. Tenant Id is route argument named 'tenant'
+ var tenantId = await TryDetectTenantId(httpContext);
+ if (string.IsNullOrEmpty(tenantId))
+ {
+ await WriteTenantIdNotFound(httpContext);
+ return;
+ }
+
+ var tenantIdentifier = new JasperFx.MultiTenancy.TenantId(tenantId);
+ var messageContext = new Wolverine.Runtime.MessageContext(_wolverineRuntime);
+ messageContext.TenantId = tenantId;
+ Wolverine.Http.Runtime.RequestIdMiddleware.Apply(httpContext, messageContext);
+
+ // The actual HTTP request handler execution
+ var result_of_GetTenantWithArgs1 = Wolverine.Http.Tests.MultiTenancy.TenantedEndpoints.GetTenantWithArgs1(messageContext, tenantIdentifier);
+
+ await WriteString(httpContext, result_of_GetTenantWithArgs1);
+
+ // Have to flush outgoing messages just in case Marten did nothing because of https://github.com/JasperFx/wolverine/issues/536
+ await messageContext.FlushOutgoingMessagesAsync().ConfigureAwait(false);
+
+ }
+
+ }
+
+ // END: GET_tenant_bus_tenant
+
+
+}
+
diff --git a/src/Http/Wolverine.Http.Tests/Internal/Generated/WolverineHandlers/GET_tenant_context_tenant.cs b/src/Http/Wolverine.Http.Tests/Internal/Generated/WolverineHandlers/GET_tenant_context_tenant.cs
new file mode 100644
index 000000000..3f99fc9c9
--- /dev/null
+++ b/src/Http/Wolverine.Http.Tests/Internal/Generated/WolverineHandlers/GET_tenant_context_tenant.cs
@@ -0,0 +1,59 @@
+//
+#pragma warning disable
+using Microsoft.AspNetCore.Routing;
+using System;
+using System.Linq;
+using Wolverine.Http;
+using Wolverine.Runtime;
+
+namespace Internal.Generated.WolverineHandlers
+{
+ // START: GET_tenant_context_tenant
+ [global::System.CodeDom.Compiler.GeneratedCode("JasperFx", "1.0.0")]
+ public sealed class GET_tenant_context_tenant : Wolverine.Http.HttpHandler
+ {
+ private readonly Wolverine.Http.WolverineHttpOptions _wolverineHttpOptions;
+ private readonly Wolverine.Runtime.IWolverineRuntime _wolverineRuntime;
+
+ public GET_tenant_context_tenant(Wolverine.Http.WolverineHttpOptions wolverineHttpOptions, Wolverine.Runtime.IWolverineRuntime wolverineRuntime) : base(wolverineHttpOptions)
+ {
+ _wolverineHttpOptions = wolverineHttpOptions;
+ _wolverineRuntime = wolverineRuntime;
+ }
+
+
+
+ public override async System.Threading.Tasks.Task Handle(Microsoft.AspNetCore.Http.HttpContext httpContext)
+ {
+
+ // Tenant Id detection
+ // 1. Tenant Id is route argument named 'tenant'
+ var tenantId = await TryDetectTenantId(httpContext);
+ if (string.IsNullOrEmpty(tenantId))
+ {
+ await WriteTenantIdNotFound(httpContext);
+ return;
+ }
+
+ var tenantIdentifier = new JasperFx.MultiTenancy.TenantId(tenantId);
+ var messageContext = new Wolverine.Runtime.MessageContext(_wolverineRuntime);
+ messageContext.TenantId = tenantId;
+ Wolverine.Http.Runtime.RequestIdMiddleware.Apply(httpContext, messageContext);
+
+ // The actual HTTP request handler execution
+ var result_of_GetTenantWithArgs1 = Wolverine.Http.Tests.MultiTenancy.TenantedEndpoints.GetTenantWithArgs1(messageContext, tenantIdentifier);
+
+ await WriteString(httpContext, result_of_GetTenantWithArgs1);
+
+ // Have to flush outgoing messages just in case Marten did nothing because of https://github.com/JasperFx/wolverine/issues/536
+ await messageContext.FlushOutgoingMessagesAsync().ConfigureAwait(false);
+
+ }
+
+ }
+
+ // END: GET_tenant_context_tenant
+
+
+}
+
diff --git a/src/Http/Wolverine.Http.Tests/Internal/Generated/WolverineHandlers/GET_tenant_route_tenant.cs b/src/Http/Wolverine.Http.Tests/Internal/Generated/WolverineHandlers/GET_tenant_route_tenant.cs
new file mode 100644
index 000000000..4b9c766cd
--- /dev/null
+++ b/src/Http/Wolverine.Http.Tests/Internal/Generated/WolverineHandlers/GET_tenant_route_tenant.cs
@@ -0,0 +1,54 @@
+//
+#pragma warning disable
+using Microsoft.AspNetCore.Routing;
+using System;
+using System.Linq;
+using Wolverine.Http;
+using Wolverine.Runtime;
+
+namespace Internal.Generated.WolverineHandlers
+{
+ // START: GET_tenant_route_tenant
+ [global::System.CodeDom.Compiler.GeneratedCode("JasperFx", "1.0.0")]
+ public sealed class GET_tenant_route_tenant : Wolverine.Http.HttpHandler
+ {
+ private readonly Wolverine.Http.WolverineHttpOptions _wolverineHttpOptions;
+ private readonly Wolverine.Runtime.IWolverineRuntime _wolverineRuntime;
+
+ public GET_tenant_route_tenant(Wolverine.Http.WolverineHttpOptions wolverineHttpOptions, Wolverine.Runtime.IWolverineRuntime wolverineRuntime) : base(wolverineHttpOptions)
+ {
+ _wolverineHttpOptions = wolverineHttpOptions;
+ _wolverineRuntime = wolverineRuntime;
+ }
+
+
+
+ public override async System.Threading.Tasks.Task Handle(Microsoft.AspNetCore.Http.HttpContext httpContext)
+ {
+
+ // Tenant Id detection
+ // 1. Tenant Id is query string value 't'
+ // 2. Wolverine.Http.Runtime.MultiTenancy.FallbackDefault
+ var tenantId = await TryDetectTenantId(httpContext);
+ var tenantIdentifier = new JasperFx.MultiTenancy.TenantId(tenantId);
+ var messageContext = new Wolverine.Runtime.MessageContext(_wolverineRuntime);
+ messageContext.TenantId = tenantId;
+ Wolverine.Http.Runtime.RequestIdMiddleware.Apply(httpContext, messageContext);
+
+ // The actual HTTP request handler execution
+ var result_of_GetTenantIdFromRoute = Wolverine.Http.Tests.MultiTenancy.TenantedEndpoints.GetTenantIdFromRoute(messageContext, tenantIdentifier);
+
+ await WriteString(httpContext, result_of_GetTenantIdFromRoute);
+
+ // Have to flush outgoing messages just in case Marten did nothing because of https://github.com/JasperFx/wolverine/issues/536
+ await messageContext.FlushOutgoingMessagesAsync().ConfigureAwait(false);
+
+ }
+
+ }
+
+ // END: GET_tenant_route_tenant
+
+
+}
+
diff --git a/src/Http/Wolverine.Http.Tests/Internal/Generated/WolverineHandlers/GET_todo_id.cs b/src/Http/Wolverine.Http.Tests/Internal/Generated/WolverineHandlers/GET_todo_id.cs
new file mode 100644
index 000000000..db0ae92cf
--- /dev/null
+++ b/src/Http/Wolverine.Http.Tests/Internal/Generated/WolverineHandlers/GET_todo_id.cs
@@ -0,0 +1,69 @@
+//
+#pragma warning disable
+using Microsoft.AspNetCore.Routing;
+using System;
+using System.Linq;
+using Wolverine.Http;
+using Wolverine.Marten.Publishing;
+using Wolverine.Runtime;
+
+namespace Internal.Generated.WolverineHandlers
+{
+ // START: GET_todo_id
+ [global::System.CodeDom.Compiler.GeneratedCode("JasperFx", "1.0.0")]
+ public sealed class GET_todo_id : Wolverine.Http.HttpHandler
+ {
+ private readonly Wolverine.Http.WolverineHttpOptions _wolverineHttpOptions;
+ private readonly Wolverine.Marten.Publishing.OutboxedSessionFactory _outboxedSessionFactory;
+ private readonly Wolverine.Runtime.IWolverineRuntime _wolverineRuntime;
+
+ public GET_todo_id(Wolverine.Http.WolverineHttpOptions wolverineHttpOptions, Wolverine.Marten.Publishing.OutboxedSessionFactory outboxedSessionFactory, Wolverine.Runtime.IWolverineRuntime wolverineRuntime) : base(wolverineHttpOptions)
+ {
+ _wolverineHttpOptions = wolverineHttpOptions;
+ _outboxedSessionFactory = outboxedSessionFactory;
+ _wolverineRuntime = wolverineRuntime;
+ }
+
+
+
+ public override async System.Threading.Tasks.Task Handle(Microsoft.AspNetCore.Http.HttpContext httpContext)
+ {
+
+ // Tenant Id detection
+ // 1. Tenant Id is first sub domain name of the request host
+ // 2. Tenant Id is request header 'tenant'
+ // 3. Tenant Id is query string value 'tenant'
+ var tenantId = await TryDetectTenantId(httpContext);
+ if (string.IsNullOrEmpty(tenantId))
+ {
+ await WriteTenantIdNotFound(httpContext);
+ return;
+ }
+
+ var tenantIdentifier = new JasperFx.MultiTenancy.TenantId(tenantId);
+ var messageContext = new Wolverine.Runtime.MessageContext(_wolverineRuntime);
+ messageContext.TenantId = tenantId;
+ // Building the Marten session using the detected tenant id
+ await using var documentSession = _outboxedSessionFactory.OpenSession(messageContext, tenantId);
+ var id = (string?)httpContext.GetRouteValue("id");
+ if(id == null)
+ {
+ httpContext.Response.StatusCode = 404;
+ return;
+ }
+
+
+ // The actual HTTP request handler execution
+ var tenantTodo_response = await Wolverine.Http.Tests.MultiTenancy.TenantedEndpoints.Get(id, ((Marten.IQuerySession)documentSession), tenantIdentifier).ConfigureAwait(false);
+
+ // Writing the response body to JSON because this was the first 'return variable' in the method signature
+ await WriteJsonAsync(httpContext, tenantTodo_response);
+ }
+
+ }
+
+ // END: GET_todo_id
+
+
+}
+
diff --git a/src/Http/Wolverine.Http.Tests/Internal/Generated/WolverineHandlers/POST_api_tenants_tenant_counters_id_inc.cs b/src/Http/Wolverine.Http.Tests/Internal/Generated/WolverineHandlers/POST_api_tenants_tenant_counters_id_inc.cs
new file mode 100644
index 000000000..7b179dc7b
--- /dev/null
+++ b/src/Http/Wolverine.Http.Tests/Internal/Generated/WolverineHandlers/POST_api_tenants_tenant_counters_id_inc.cs
@@ -0,0 +1,87 @@
+//
+#pragma warning disable
+using Microsoft.AspNetCore.Routing;
+using System;
+using System.Linq;
+using Wolverine.Http;
+using Wolverine.Marten.Publishing;
+using Wolverine.Runtime;
+
+namespace Internal.Generated.WolverineHandlers
+{
+ // START: POST_api_tenants_tenant_counters_id_inc
+ [global::System.CodeDom.Compiler.GeneratedCode("JasperFx", "1.0.0")]
+ public sealed class POST_api_tenants_tenant_counters_id_inc : Wolverine.Http.HttpHandler
+ {
+ private readonly Wolverine.Http.WolverineHttpOptions _wolverineHttpOptions;
+ private readonly Wolverine.Runtime.IWolverineRuntime _wolverineRuntime;
+ private readonly Wolverine.Marten.Publishing.OutboxedSessionFactory _outboxedSessionFactory;
+
+ public POST_api_tenants_tenant_counters_id_inc(Wolverine.Http.WolverineHttpOptions wolverineHttpOptions, Wolverine.Runtime.IWolverineRuntime wolverineRuntime, Wolverine.Marten.Publishing.OutboxedSessionFactory outboxedSessionFactory) : base(wolverineHttpOptions)
+ {
+ _wolverineHttpOptions = wolverineHttpOptions;
+ _wolverineRuntime = wolverineRuntime;
+ _outboxedSessionFactory = outboxedSessionFactory;
+ }
+
+
+
+ public override async System.Threading.Tasks.Task Handle(Microsoft.AspNetCore.Http.HttpContext httpContext)
+ {
+ var messageContext = new Wolverine.Runtime.MessageContext(_wolverineRuntime);
+ // Building the Marten session
+ await using var documentSession = _outboxedSessionFactory.OpenSession(messageContext);
+ string Id_rawValue = (string?)httpContext.GetRouteValue("Id");
+ System.Guid Id = default;
+
+ if (Id_rawValue != null && System.Guid.TryParse(Id_rawValue, System.Globalization.CultureInfo.InvariantCulture, out Id))
+ {
+
+ }
+
+ else
+ {
+ httpContext.Response.StatusCode = 404;
+ return;
+ }
+
+
+ // Try to load the existing saga document
+ var counter_Id = await documentSession.LoadAsync(Id, httpContext.RequestAborted).ConfigureAwait(false);
+ // 404 if this required object is null
+ if (counter_Id == null)
+ {
+ httpContext.Response.StatusCode = 404;
+ return;
+ }
+
+
+ // The actual HTTP request handler execution
+ (var result, var martenOp) = Wolverine.Http.Tests.Bugs.CounterEndpoint.Increment(counter_Id);
+
+ if (martenOp != null)
+ {
+
+ // Placed by Wolverine's ISideEffect policy
+ martenOp.Execute(documentSession);
+
+ }
+
+
+ // Save all pending changes to this Marten session
+ await documentSession.SaveChangesAsync(httpContext.RequestAborted).ConfigureAwait(false);
+
+
+ // Have to flush outgoing messages just in case Marten did nothing because of https://github.com/JasperFx/wolverine/issues/536
+ await messageContext.FlushOutgoingMessagesAsync().ConfigureAwait(false);
+
+ await result.ExecuteAsync(httpContext).ConfigureAwait(false);
+ }
+
+ }
+
+ // END: POST_api_tenants_tenant_counters_id_inc
+
+
+}
+
diff --git a/src/Http/Wolverine.Http.Tests/Internal/Generated/WolverineHandlers/POST_api_tenants_tenant_counters_id_inc2.cs b/src/Http/Wolverine.Http.Tests/Internal/Generated/WolverineHandlers/POST_api_tenants_tenant_counters_id_inc2.cs
new file mode 100644
index 000000000..3d5eb8ff8
--- /dev/null
+++ b/src/Http/Wolverine.Http.Tests/Internal/Generated/WolverineHandlers/POST_api_tenants_tenant_counters_id_inc2.cs
@@ -0,0 +1,88 @@
+//
+#pragma warning disable
+using Microsoft.AspNetCore.Routing;
+using System;
+using System.Linq;
+using Wolverine.Http;
+using Wolverine.Marten.Publishing;
+using Wolverine.Runtime;
+
+namespace Internal.Generated.WolverineHandlers
+{
+ // START: POST_api_tenants_tenant_counters_id_inc2
+ [global::System.CodeDom.Compiler.GeneratedCode("JasperFx", "1.0.0")]
+ public sealed class POST_api_tenants_tenant_counters_id_inc2 : Wolverine.Http.HttpHandler
+ {
+ private readonly Wolverine.Http.WolverineHttpOptions _wolverineHttpOptions;
+ private readonly Wolverine.Runtime.IWolverineRuntime _wolverineRuntime;
+ private readonly Wolverine.Marten.Publishing.OutboxedSessionFactory _outboxedSessionFactory;
+
+ public POST_api_tenants_tenant_counters_id_inc2(Wolverine.Http.WolverineHttpOptions wolverineHttpOptions, Wolverine.Runtime.IWolverineRuntime wolverineRuntime, Wolverine.Marten.Publishing.OutboxedSessionFactory outboxedSessionFactory) : base(wolverineHttpOptions)
+ {
+ _wolverineHttpOptions = wolverineHttpOptions;
+ _wolverineRuntime = wolverineRuntime;
+ _outboxedSessionFactory = outboxedSessionFactory;
+ }
+
+
+
+ public override async System.Threading.Tasks.Task Handle(Microsoft.AspNetCore.Http.HttpContext httpContext)
+ {
+ var messageContext = new Wolverine.Runtime.MessageContext(_wolverineRuntime);
+ // Building the Marten session
+ await using var documentSession = _outboxedSessionFactory.OpenSession(messageContext);
+ string Id_rawValue = (string?)httpContext.GetRouteValue("Id");
+ System.Guid Id = default;
+
+ if (Id_rawValue != null && System.Guid.TryParse(Id_rawValue, System.Globalization.CultureInfo.InvariantCulture, out Id))
+ {
+
+ }
+
+ else
+ {
+ httpContext.Response.StatusCode = 404;
+ return;
+ }
+
+
+ // Try to load the existing saga document
+ var counter_Id = await documentSession.LoadAsync(Id, httpContext.RequestAborted).ConfigureAwait(false);
+ // 404 if this required object is null
+ if (counter_Id == null)
+ {
+ httpContext.Response.StatusCode = 404;
+ return;
+ }
+
+
+ // The actual HTTP request handler execution
+ var martenOp = Wolverine.Http.Tests.Bugs.CounterEndpoint.Increment2(counter_Id);
+
+ if (martenOp != null)
+ {
+
+ // Placed by Wolverine's ISideEffect policy
+ martenOp.Execute(documentSession);
+
+ }
+
+
+ // Save all pending changes to this Marten session
+ await documentSession.SaveChangesAsync(httpContext.RequestAborted).ConfigureAwait(false);
+
+
+ // Have to flush outgoing messages just in case Marten did nothing because of https://github.com/JasperFx/wolverine/issues/536
+ await messageContext.FlushOutgoingMessagesAsync().ConfigureAwait(false);
+
+ // Wolverine automatically sets the status code to 204 for empty responses
+ if (httpContext.Response is { HasStarted: false, StatusCode: 200 }) httpContext.Response.StatusCode = 204;
+ }
+
+ }
+
+ // END: POST_api_tenants_tenant_counters_id_inc2
+
+
+}
+
diff --git a/src/Http/Wolverine.Http.Tests/Internal/Generated/WolverineHandlers/POST_tenant_tenant_formdata.cs b/src/Http/Wolverine.Http.Tests/Internal/Generated/WolverineHandlers/POST_tenant_tenant_formdata.cs
new file mode 100644
index 000000000..a9681ff9a
--- /dev/null
+++ b/src/Http/Wolverine.Http.Tests/Internal/Generated/WolverineHandlers/POST_tenant_tenant_formdata.cs
@@ -0,0 +1,50 @@
+//
+#pragma warning disable
+using Microsoft.AspNetCore.Routing;
+using System;
+using System.Linq;
+using Wolverine.Http;
+
+namespace Internal.Generated.WolverineHandlers
+{
+ // START: POST_tenant_tenant_formdata
+ [global::System.CodeDom.Compiler.GeneratedCode("JasperFx", "1.0.0")]
+ public sealed class POST_tenant_tenant_formdata : Wolverine.Http.HttpHandler
+ {
+ private readonly Wolverine.Http.WolverineHttpOptions _wolverineHttpOptions;
+
+ public POST_tenant_tenant_formdata(Wolverine.Http.WolverineHttpOptions wolverineHttpOptions) : base(wolverineHttpOptions)
+ {
+ _wolverineHttpOptions = wolverineHttpOptions;
+ }
+
+
+
+ public override async System.Threading.Tasks.Task Handle(Microsoft.AspNetCore.Http.HttpContext httpContext)
+ {
+
+ // Tenant Id detection
+ // 1. Tenant Id is route argument named 'tenant'
+ var tenantId = await TryDetectTenantId(httpContext);
+ if (string.IsNullOrEmpty(tenantId))
+ {
+ await WriteTenantIdNotFound(httpContext);
+ return;
+ }
+
+ var tenantIdentifier = new JasperFx.MultiTenancy.TenantId(tenantId);
+ var value = httpContext.Request.Form["value"];
+
+ // The actual HTTP request handler execution
+ var result_of_GetTenantIdWithFormData = Wolverine.Http.Tests.MultiTenancy.TenantedEndpoints.GetTenantIdWithFormData(value, tenantIdentifier);
+
+ await WriteString(httpContext, result_of_GetTenantIdWithFormData);
+ }
+
+ }
+
+ // END: POST_tenant_tenant_formdata
+
+
+}
+
diff --git a/src/Http/Wolverine.Http.Tests/Internal/Generated/WolverineHandlers/POST_todo_create.cs b/src/Http/Wolverine.Http.Tests/Internal/Generated/WolverineHandlers/POST_todo_create.cs
new file mode 100644
index 000000000..01f4e49d1
--- /dev/null
+++ b/src/Http/Wolverine.Http.Tests/Internal/Generated/WolverineHandlers/POST_todo_create.cs
@@ -0,0 +1,81 @@
+//
+#pragma warning disable
+using Microsoft.AspNetCore.Routing;
+using System;
+using System.Linq;
+using Wolverine.Http;
+using Wolverine.Marten.Publishing;
+using Wolverine.Runtime;
+
+namespace Internal.Generated.WolverineHandlers
+{
+ // START: POST_todo_create
+ [global::System.CodeDom.Compiler.GeneratedCode("JasperFx", "1.0.0")]
+ public sealed class POST_todo_create : Wolverine.Http.HttpHandler
+ {
+ private readonly Wolverine.Http.WolverineHttpOptions _wolverineHttpOptions;
+ private readonly Wolverine.Marten.Publishing.OutboxedSessionFactory _outboxedSessionFactory;
+ private readonly Wolverine.Runtime.IWolverineRuntime _wolverineRuntime;
+
+ public POST_todo_create(Wolverine.Http.WolverineHttpOptions wolverineHttpOptions, Wolverine.Marten.Publishing.OutboxedSessionFactory outboxedSessionFactory, Wolverine.Runtime.IWolverineRuntime wolverineRuntime) : base(wolverineHttpOptions)
+ {
+ _wolverineHttpOptions = wolverineHttpOptions;
+ _outboxedSessionFactory = outboxedSessionFactory;
+ _wolverineRuntime = wolverineRuntime;
+ }
+
+
+
+ public override async System.Threading.Tasks.Task Handle(Microsoft.AspNetCore.Http.HttpContext httpContext)
+ {
+
+ // Tenant Id detection
+ // 1. Tenant Id is first sub domain name of the request host
+ // 2. Tenant Id is request header 'tenant'
+ // 3. Tenant Id is query string value 'tenant'
+ var tenantId = await TryDetectTenantId(httpContext);
+ if (string.IsNullOrEmpty(tenantId))
+ {
+ await WriteTenantIdNotFound(httpContext);
+ return;
+ }
+
+ var messageContext = new Wolverine.Runtime.MessageContext(_wolverineRuntime);
+ messageContext.TenantId = tenantId;
+ // Building the Marten session using the detected tenant id
+ await using var documentSession = _outboxedSessionFactory.OpenSession(messageContext, tenantId);
+ var tenantIdentifier = new JasperFx.MultiTenancy.TenantId(tenantId);
+ // Reading the request body via JSON deserialization
+ var (command, jsonContinue) = await ReadJsonAsync(httpContext);
+ if (jsonContinue == Wolverine.HandlerContinuation.Stop) return;
+
+ // The actual HTTP request handler execution
+ var martenOp = Wolverine.Http.Tests.MultiTenancy.TenantedEndpoints.Create(command, tenantIdentifier);
+
+ if (martenOp != null)
+ {
+
+ // Placed by Wolverine's ISideEffect policy
+ martenOp.Execute(documentSession);
+
+ }
+
+
+ // Save all pending changes to this Marten session
+ await documentSession.SaveChangesAsync(httpContext.RequestAborted).ConfigureAwait(false);
+
+
+ // Have to flush outgoing messages just in case Marten did nothing because of https://github.com/JasperFx/wolverine/issues/536
+ await messageContext.FlushOutgoingMessagesAsync().ConfigureAwait(false);
+
+ // Wolverine automatically sets the status code to 204 for empty responses
+ if (httpContext.Response is { HasStarted: false, StatusCode: 200 }) httpContext.Response.StatusCode = 204;
+ }
+
+ }
+
+ // END: POST_todo_create
+
+
+}
+
diff --git a/src/Persistence/LoadTesting/LoadTesting.csproj b/src/Persistence/LoadTesting/LoadTesting.csproj
new file mode 100644
index 000000000..7b1e349f7
--- /dev/null
+++ b/src/Persistence/LoadTesting/LoadTesting.csproj
@@ -0,0 +1,20 @@
+
+
+
+ Exe
+ enable
+ enable
+
+
+
+
+
+
+
+
+
+ Servers.cs
+
+
+
+
diff --git a/src/Persistence/LoadTesting/Program.cs b/src/Persistence/LoadTesting/Program.cs
new file mode 100644
index 000000000..bf1abdee0
--- /dev/null
+++ b/src/Persistence/LoadTesting/Program.cs
@@ -0,0 +1,66 @@
+// See https://aka.ms/new-console-template for more information
+
+using IntegrationTests;
+using JasperFx;
+using JasperFx.Events.Daemon;
+using JasperFx.Events.Projections;
+using JasperFx.Resources;
+using LoadTesting;
+using LoadTesting.Trips;
+using Marten;
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.Hosting;
+using Wolverine;
+using Wolverine.Marten;
+using Wolverine.RabbitMQ;
+using Wolverine.Transports;
+
+return await Host.CreateDefaultBuilder()
+ .UseWolverine(opts =>
+ {
+ opts.Policies.UseDurableLocalQueues();
+
+ opts.Services.AddMarten(m =>
+ {
+ m.Connection(Servers.PostgresConnectionString);
+ m.DatabaseSchemaName = "load_testing";
+
+ m.DisableNpgsqlLogging = true;
+
+ m.Schema.For();
+
+ m.Projections.Add(ProjectionLifecycle.Async);
+ m.Projections.Add(ProjectionLifecycle.Async);
+ m.Projections.Add(ProjectionLifecycle.Async);
+ }).AddAsyncDaemon(DaemonMode.Solo).IntegrateWithWolverine();
+
+ opts.ServiceName = "TripPublisher";
+
+ opts.Durability.Mode = DurabilityMode.Solo;
+ opts.ApplicationAssembly = typeof(Program).Assembly;
+ opts.EnableAutomaticFailureAcks = false;
+
+ opts.Policies.AutoApplyTransactions();
+
+ opts.Services.AddSingleton();
+
+ // Force it to use Rabbit MQ
+ opts.Policies.DisableConventionalLocalRouting();
+ opts.UseRabbitMq().UseConventionalRouting().AutoProvision();
+
+ opts.Policies.UseDurableInboxOnAllListeners();
+ opts.Policies.UseDurableOutboxOnAllSendingEndpoints();
+
+ opts.LocalQueueFor().UseDurableInbox();
+
+ //opts.Services.AddHostedService();
+ opts.Services.AddResourceSetupOnStartup();
+
+ opts.Policies.AllLocalQueues(listener =>
+ {
+ listener.UseDurableInbox();
+ listener.Sequential();
+ });
+
+
+ }).RunJasperFxCommands(args);
\ No newline at end of file
diff --git a/src/Persistence/LoadTesting/Publisher.cs b/src/Persistence/LoadTesting/Publisher.cs
new file mode 100644
index 000000000..1715ad2ad
--- /dev/null
+++ b/src/Persistence/LoadTesting/Publisher.cs
@@ -0,0 +1,100 @@
+using ImTools;
+using LoadTesting.Trips;
+using Microsoft.Extensions.Hosting;
+using Microsoft.Extensions.Logging;
+using Wolverine.Runtime;
+
+namespace LoadTesting;
+
+public class KickOffPublishing : IHostedService
+{
+ private readonly Publisher _publisher;
+ private readonly IWolverineRuntime _runtime;
+ private readonly ILogger _logger;
+
+ public KickOffPublishing(Publisher publisher, IWolverineRuntime runtime, ILogger logger)
+ {
+ _publisher = publisher;
+ _runtime = runtime;
+ _logger = logger;
+ }
+
+ public async Task StartAsync(CancellationToken cancellationToken)
+ {
+ var bus = new MessageBus(_runtime);
+ var messages = _publisher.InitialMessages();
+ foreach (var message in messages)
+ {
+
+ await bus.PublishAsync(message);
+ _logger.LogInformation("Published initial message {Message}", message);
+ }
+ }
+
+ public Task StopAsync(CancellationToken cancellationToken)
+ {
+ return Task.CompletedTask;
+ }
+}
+
+public class Publisher
+{
+ private ImHashMap _streams = ImHashMap.Empty;
+
+ public Publisher()
+ {
+ var streams = TripStream.RandomStreams(10);
+ foreach (var stream in streams)
+ {
+ _streams = _streams.AddOrUpdate(stream.Id, stream);
+ }
+ }
+
+ public IEnumerable