diff --git a/docs/.vitepress/config.mts b/docs/.vitepress/config.mts index c23ebcaa0..fbc372a0a 100644 --- a/docs/.vitepress/config.mts +++ b/docs/.vitepress/config.mts @@ -101,7 +101,8 @@ const config: UserConfig = { {text: 'Execution Timeouts', link: '/guide/handlers/timeout'}, {text: 'Fluent Validation Middleware', link: '/guide/handlers/fluent-validation'}, {text: 'Sticky Handler to Endpoint Assignments', link: '/guide/handlers/sticky'}, - {text: 'Message Batching', link: '/guide/handlers/batching'} + {text: 'Message Batching', link: '/guide/handlers/batching'}, + {text: 'Persistence Helpers', link: '/guide/handlers/persistence'} ] }, ] diff --git a/docs/guide/durability/efcore.md b/docs/guide/durability/efcore.md index 722f1163b..73c320d22 100644 --- a/docs/guide/durability/efcore.md +++ b/docs/guide/durability/efcore.md @@ -249,7 +249,7 @@ public async Task Post( await outbox.SaveChangesAndFlushMessagesAsync(); } ``` -snippet source | anchor +snippet source | anchor Or use the `IDbContextOutbox` as shown below, but in this case you will need to explicitly call `Enroll()` on @@ -291,10 +291,20 @@ public async Task Post3( await outbox.SaveChangesAndFlushMessagesAsync(); } ``` -snippet source | anchor +snippet source | anchor ## As Saga Storage There's actually nothing to do other than to make a mapping of the `Saga` subclass that's your stateful saga inside a registered `DbContext`. + +## Storage Side Effects + +This integration includes full support for the [storage action side effects](/guide/handlers/side-effects.html#storage-side-effects) +model when using EF Core with Wolverine. The only exception is that the `Store` "upsert" operation from the +side effects translates to an EF Core `DbContext` update. + +## Entity Attribute Loading + +The EF Core integration is able to completely support the [Entity attribute usage](/guide/handlers/persistence.html#automatically-loading-entities-to-method-parameters). \ No newline at end of file diff --git a/docs/guide/durability/marten/index.md b/docs/guide/durability/marten/index.md index 31e4485d1..be7a33358 100644 --- a/docs/guide/durability/marten/index.md +++ b/docs/guide/durability/marten/index.md @@ -95,6 +95,9 @@ Using the `IntegrateWithWolverine()` extension method behind your call to `AddMa * Makes Marten the active [saga storage](/guide/durability/sagas) for Wolverine * Adds transactional middleware using Marten to your Wolverine application +## Entity Attribute Loading + +The EF Core integration is able to completely support the [Entity attribute usage](/guide/handlers/persistence.html#automatically-loading-entities-to-method-parameters). ## Marten as Outbox diff --git a/docs/guide/durability/marten/operations.md b/docs/guide/durability/marten/operations.md index f543ace65..7e1f2b1bb 100644 --- a/docs/guide/durability/marten/operations.md +++ b/docs/guide/durability/marten/operations.md @@ -5,6 +5,16 @@ You can certainly write your own `IMartenOp` implementations and use them as ret handlers ::: +::: info +This integration includes full support for the [storage action side effects](/guide/handlers/side-effects.html#storage-side-effects) +model when using Marten with Wolverine. +::: + +::: tip +This integration also includes full support for the [storage action side effects](/guide/handlers/side-effects.html#storage-side-effects) +model when using Marten~~~~ with Wolverine. +::: + The `Wolverine.Marten` library includes some helpers for Wolverine [side effects](/guide/handlers/side-effects) using Marten with the `IMartenOp` interface: @@ -19,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: @@ -66,5 +76,38 @@ be a pure function that can be easily unit tested through measuring the expected helps you utilize synchronous methods for your logic, even though at runtime Wolverine itself will be wrapping asynchronous code about your simpler, synchronous code. +## Returning Multiple Marten Side Effects + +Due to (somewhat) popular demand, Wolverine lets you return zero to many `IMartenOp` operations as side effects +from a message handler or HTTP endpoint method like so: + + + +```cs +// Just keep in mind that this "example" was rigged up for test coverage +public static IEnumerable Handle(AppendManyNamedDocuments command) +{ + var number = 1; + foreach (var name in command.Names) + { + yield return MartenOps.Store(new NamedDocument{Id = name, Number = number++}); + } +} +``` +snippet source | anchor + + +Wolverine will pick up on any return type that can be cast to `IEnumerable`, so for example: + +* `IEnumerable` +* `IMartenOp[]` +* `List` + +And you get the point. Wolverine is not (yet) smart enough to know that an array or enumerable of a concrete +type of `IMartenOp` is a side effect. + +Like any other "side effect", you could technically return this as the main return type of a method or as part of a +tuple. + diff --git a/docs/guide/durability/marten/transactional-middleware.md b/docs/guide/durability/marten/transactional-middleware.md index 37fd3b1ec..7901323b3 100644 --- a/docs/guide/durability/marten/transactional-middleware.md +++ b/docs/guide/durability/marten/transactional-middleware.md @@ -112,7 +112,7 @@ public class CommandsAreTransactional : IHandlerPolicy // for each chain chains .Where(chain => chain.MessageType.Name.EndsWith("Command")) - .Each(chain => chain.Middleware.Add(new TransactionalFrame(chain))); + .Each(chain => chain.Middleware.Add(new CreateDocumentSessionFrame(chain))); } } ``` diff --git a/docs/guide/durability/ravendb.md b/docs/guide/durability/ravendb.md index 9ccdc0464..63af1bfba 100644 --- a/docs/guide/durability/ravendb.md +++ b/docs/guide/durability/ravendb.md @@ -224,7 +224,14 @@ public static class RavenOps snippet source | anchor -See the Wolverine [side effects](/guide/handlers/side-effects) model for more information. +See the Wolverine [side effects](/guide/handlers/side-effects) model for more information. + +This integration also includes full support for the [storage action side effects](/guide/handlers/side-effects.html#storage-side-effects) +model when using RavenDb with Wolverine. + +## Entity Attribute Loading + +The RavenDb integration is able to completely support the [Entity attribute usage](/guide/handlers/persistence.html#automatically-loading-entities-to-method-parameters). diff --git a/docs/guide/handlers/persistence.md b/docs/guide/handlers/persistence.md new file mode 100644 index 000000000..18e0844d5 --- /dev/null +++ b/docs/guide/handlers/persistence.md @@ -0,0 +1,151 @@ +# Persistence Helpers + +Philosophically, Wolverine is trying to enable you to write the message handlers or HTTP endpoint +methods with low ceremony code that's easy to test and easy to reason about. To that end, Wolverine +has quite a few tricks to utilize your persistence tooling from your handler or HTTP endpoint code +without having to directly couple your behavioral code to persistence infrastructure: + +* The [storage action side effect model](/guide/handlers/side-effects.html#storage-side-effects) for pure function handlers that involve database "writes" +* The [aggregate handler workflow](/guide/durability/marten/event-sourcing) with Marten for highly testable CQRS + Event Sourcing systems +* Specific [integration with Marten and Wolverine.HTTP](/guide/http/marten) + +## Automatically Loading Entities to Method Parameters + +A common need when building Wolverine message handlers or HTTP endpoints is to need to load +an entity object based on an identity value in either the message itself, the HTTP request body, or +an HTTP route argument. In these cases, you'll generally pluck the correct value out of the +message or route arguments, then call into an EF Core `DbContext` or a Marten/RavenDb `IDocumentSession` +to load the entity for you before proceeding on with your work. Since this usage is so common, +Wolverine has the `[Wolverine.Persistence.Entity]` attribute to just do that for you and have the right entity "pushed" into +your message handler. + +Here's a simple example of a message handler that's also a valid Wolverine.HTTP endpoint using this attribute. First though, +the message type and/or HTTP request body: + + + +```cs +public record RenameTodo(string Id, string Name); +``` +snippet source | anchor + + +and the handler & endpoint code handling that message type: + + + +```cs +// Use "Id" as the default member +[WolverinePost("/api/todo/update")] +public static Update Handle( + // The first argument is always the incoming message + RenameTodo command, + + // By using this attribute, we're telling Wolverine + // to load the Todo entity from the configured + // persistence of the app using a member on the + // incoming message type + [Entity] Todo2 todo) +{ + // Do your actual business logic + todo.Name = command.Name; + + // Tell Wolverine that you want this entity + // updated in persistence + return Storage.Update(todo); +} +``` +snippet source | anchor + + +In the code above, the `Todo2` argument would be filled by trying to load that `Todo2` entity +from persistence using the value of `RenameTodo.Id`. If you were using Marten as your persistence +mechanism, this would be using `IDocumentSession.LoadAsync(id)` to load the entity with the RavenDb usage being similar. If +you were using EF Core and had an `Todo2DbContext` service registered in your system, it would +be using `Todo2DbContext.FindAsync(id)`. + +By default, Wolverine is assuming that any parameter value marked with `[Entity]` is required, so if the `Todo2` entity was not found in the database, then: + +* As a message handler, it will just log that the entity could not be found and otherwise exit cleanly without doing any further processing +* As an HTTP endpoint, the handler would write out a status code of 404 (not found) and exit otherwise + +If you need or want any other kind of failure handling on the entity not being found, you'll need to +use explicit code instead, maybe with a `LoadAsync()` "before" method to still keep your main +handler or endpoint method a *pure function*. + +If you genuinely don't need the `[Entity]` value to be required, you can do this instead: + + + +```cs +[WolverinePost("/api/todo/maybecomplete")] +public static IStorageAction Handle(MaybeCompleteTodo command, [Entity(Required = false)] Todo2? todo) +{ + if (todo == null) return Storage.Nothing(); + todo.IsComplete = true; + return Storage.Update(todo); +} +``` +snippet source | anchor + + +So far, all of the examples have depended on a fall back to looking for either a case insensitive match "id" +match on the message members for message handlers or the route arguments, then request input members +for HTTP endpoints. Wolverine will also look for "[Entity Type Name]Id", so in the case of `Todo2`, it would +look as well for a more specific `Todo2Id` member or route argument for the identity value. + +You can of course override this by just telling Wolverine what member name or route argument name +should have the identity like this: + + + +```cs +// Okay, I still used "id", but it *could* be something different here! +[WolverineGet("/api/todo/{id}")] +public static Todo2 Get([Entity("id")] Todo2 todo) => todo; +``` +snippet source | anchor + + +If you have any conflict between whether the identity should be found on either the route arguments +or request body, you can specify the identity value source through the `EntityAttribute.ValueSource` property +to one of these values: + + + +```cs +public enum ValueSource +{ + /// + /// This value can be sourced by any mechanism that matches the name. This is the default. + /// + Anything, + + /// + /// The value should be sourced by a property or field on the message type or HTTP request type + /// + InputMember, + + /// + /// The value should be sourced by a route argument of an HTTP request + /// + RouteValue +} +``` +snippet source | anchor + + +Some other facts to know about `[Entity]` usage: + +* Supported by the Marten, EF Core, and RavenDb integration +* For EF Core usage, Wolverine has to be able to figure out which `DbContext` type persists the entity type of the parameter +* In all cases, Wolverine is trying to "know" what the identity type for the entity type is (`Guid`? `int`? Something else?) from the underlying persistence tooling and use that to help parse route arguments as needed +* `[Entity]` cannot support any kind of composite key or identity +* `[Entity]` can be used for both HTTP endpoints and message handler methods +* `[Entity]` can be used for `Before` / `Validate` methods in compound handlers +* If an `[Entity]` attribute is used in the main handler or endpoint method, you can still resolve the same entity type as a parameter to a `Before` method without needing to use the attribute again + +::: tip +As with other kinds of Wolverine "magic", lean on the [pre-generated code](/guide/codegen) to let Wolverine explain +what it's doing with your method signatures. +::: diff --git a/docs/guide/handlers/side-effects.md b/docs/guide/handlers/side-effects.md index 1afb69b18..0319ebaf2 100644 --- a/docs/guide/handlers/side-effects.md +++ b/docs/guide/handlers/side-effects.md @@ -123,3 +123,135 @@ available to the actual message handler like: You can find more usages of side effect return values in the [Marten side effect operations](/guide/durability/marten/operations). +## Storage Side Effects + +::: info +Wolverine may not be a functional programming toolset per se, but it's at least "FP-adjacent." The storage +side effects explained in this section are arguably side effect monads from functional programming where the goal +is to keep the behavioral logic function "pure" so that it can be easily tested and reasoned about without +any of the actual persistence infrastructure being involved. The actual "side effect" object will be part +of invoking the actual persistence tooling to make writes to the underlying database. +::: + +It's more than likely that your application using Wolverine will be using some kind of persistence +tooling that you use to load and persist entity objects. Wolverine has first class support for designating +entity values for persistence as part of its philosophy of utilizing [pure functions](https://en.wikipedia.org/wiki/Pure_function) for the behavioral +part of message handlers or HTTP endpoint methods -- *and this is advantageous because it allows +you to write behavioral code in your message handlers or HTTP endpoints that is easy to unit test +and reason about without having to employ high ceremony layering approaches. + +::: info +Returning any kind of `IStorageAction` type or the `UnitOfWork` type from a handler method or HTTP endpoint +method will automatically apply transactional middleware around that handler or endpoint regardless of whether auto +transactions are configured. +::: + +As a quick, concrete example, let's say that you have a message handler that conditionally creates a new `Item` if +the request doesn't contain any profanity (it's late and I'm struggling to come up with sample use cases). With +the storage side effect approach, you could code that like this: + + + +```cs +public record CreateItem(Guid Id, string Name); + +public static class CreateItemHandler +{ + // It's always a struggle coming up with sample use cases + public static IStorageAction Handle( + CreateItem command, + IProfanityDetector detector) + { + // First see if the name is valid + if (detector.HasProfanity(command.Name)) + { + // and if not, do nothing + return Storage.Nothing(); + } + + return Storage.Insert(new Item + { + Id = command.Id, + Name = command.Name + }); + } +} +``` +snippet source | anchor + + +In the handler above, if we return `Wolverine.Persistence.IStorageAction`, that's recognized by Wolverine as a +side effect that means an action should be taken to persist or delete an entity by the underlying persistence mechanism. +Assuming that your application is using an EF Core service named `ItemDbContext` to persist +the `Item` entities, the storage action side effect workflow at runtime is something like this: + +```mermaid +sequenceDiagram + note right of MessageHandler: MessageHandler is generated by Wolverine + MessageHandler->>CreateItemHandler:Handle() + CreateItemHandler-->>MessageHandler: storage action side effect + note left of EfCoreStorageActionApplier: This is Wolverine relaying the side effect to the DbContext + MessageHandler->>EfCoreStorageActionApplier:Apply(ItemDbContext, storage action side effect) + MessageHandler->>ItemDbContext:SaveChangesAsync() +``` + +Wolverine itself is generating the necessary code to take the side effect object you returned and +apply that to the right persistence tool for the wrapped entity. In all cases, if you're ever +curious or having any trouble understanding what Wolverine is doing with your side effect return +types, look at the [pre-generated message handler code](/guide/codegen). + +As +a convenience, you can create these side effect return values by using the static factory methods on the `Wolverine.Persistence.Storage` class, +or just directly build a return value like: + +```csharp +return new Insert(new Item{}); +``` + +This storage side effect model can support these operations: + +1. `Insert` -- some persistence tools will use their "upsert" functionality here +2. `Update` +3. `Store` -- which means "upsert" for the persistence tools like Marten or RavenDb that natively support upserts. For EF Core, this is an `Update` +4. `Delete` -- delete that entity +5. `Nothing` -- do absolutely nothing, but at least you don't have to return a null + +In your method signatures, you can: + +* Return `IStorageAction` which allows your handler or HTTP endpoint method to have some logic about whether the wrapped entity should be inserted, updated, deleted, or do absolutely nothing depending on business rules +* Return a specific `Delete` or `Insert` or other storage action types +* Use any of these types in a tuple return value just like any other type of side effect value +* Return null values, in which case Wolverine is smart enough to do nothing + +::: info +As of now, this usage is supported by Wolverine's [Marten](/guide/durability/marten/), [EF Core](/guide/durability/efcore), and [RavenDb](/guide/durability/ravendb) integrations. +Do note that not every persistence integration supports the `Store()` ["upsert"](https://en.wiktionary.org/wiki/upsert) capability (EF Core does not). +::: + +If you want to return a variable number of storage actions from a message handler, you'll want +to use the `Wolverine.Persistence.UnitOfWork` type as a return type as shown below: + + + +```cs +public record StoreMany(string[] Adds); + +public static class StoreManyHandler +{ + public static UnitOfWork Handle(StoreMany command) + { + var uow = new UnitOfWork(); + foreach (var add in command.Adds) + { + uow.Insert(new Todo { Id = add }); + } + + return uow; + } +} +``` +snippet source | anchor + + +The `UnitOfWork` is really just a `List>` that can relay zero to many storage +actions to your underlying persistence tooling. diff --git a/docs/guide/http/routing.md b/docs/guide/http/routing.md index a5d62af45..dc2076558 100644 --- a/docs/guide/http/routing.md +++ b/docs/guide/http/routing.md @@ -65,7 +65,7 @@ public static readonly Dictionary TypeOutputs = new() { typeof(DateTimeOffset), typeof(DateTimeOffset).FullName! } }; ``` -snippet source | anchor +snippet source | anchor ::: warning 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..a6a929db6 --- /dev/null +++ b/src/Http/Wolverine.Http.Tests/Internal/Generated/WolverineHandlers/POST_api_tenants_tenant_counters_id_inc.cs @@ -0,0 +1,77 @@ +// +#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 + public 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) + { + if (!System.Guid.TryParse((string)httpContext.GetRouteValue("id"), out var id)) + { + httpContext.Response.StatusCode = 404; + return; + } + + + var messageContext = new Wolverine.Runtime.MessageContext(_wolverineRuntime); + // Building the Marten session + await using var documentSession = _outboxedSessionFactory.OpenSession(messageContext); + var counter = await documentSession.LoadAsync(id, httpContext.RequestAborted).ConfigureAwait(false); + // 404 if this required object is null + if (counter == null) + { + httpContext.Response.StatusCode = 404; + return; + } + + + // The actual HTTP request handler execution + (var result, var martenOp) = Wolverine.Http.Tests.Bugs.CounterEndpoint.Increment(counter); + + 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..196a83f25 --- /dev/null +++ b/src/Http/Wolverine.Http.Tests/Internal/Generated/WolverineHandlers/POST_api_tenants_tenant_counters_id_inc2.cs @@ -0,0 +1,78 @@ +// +#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 + public 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); + if (!System.Guid.TryParse((string)httpContext.GetRouteValue("id"), out var id)) + { + httpContext.Response.StatusCode = 404; + return; + } + + + var counter = await documentSession.LoadAsync(id, httpContext.RequestAborted).ConfigureAwait(false); + // 404 if this required object is null + if (counter == null) + { + httpContext.Response.StatusCode = 404; + return; + } + + + // The actual HTTP request handler execution + var martenOp = Wolverine.Http.Tests.Bugs.CounterEndpoint.Increment2(counter); + + 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.HasStarted) httpContext.Response.StatusCode = 204; + } + + } + + // END: POST_api_tenants_tenant_counters_id_inc2 + + +} + diff --git a/src/Http/Wolverine.Http.Tests/using_storage_actions_and_entity_attribute.cs b/src/Http/Wolverine.Http.Tests/using_storage_actions_and_entity_attribute.cs new file mode 100644 index 000000000..489ee9bec --- /dev/null +++ b/src/Http/Wolverine.Http.Tests/using_storage_actions_and_entity_attribute.cs @@ -0,0 +1,268 @@ +using Alba; +using Marten; +using Shouldly; +using Wolverine.Tracking; +using WolverineWebApi.Todos; + +namespace Wolverine.Http.Tests; + +public class using_storage_actions_and_entity_attribute : IntegrationContext +{ + public using_storage_actions_and_entity_attribute(AppFixture fixture) : base(fixture) + { + } + + // These two methods will be changed + public async Task Load(string id) + { + using var session = Host.DocumentStore().LightweightSession(); + return await session.LoadAsync(id); + } + + public async Task Persist(Todo2 todo) + { + using var session = Host.DocumentStore().LightweightSession(); + session.Store(todo); + await session.SaveChangesAsync(); + } + + [Fact] + public async Task use_insert_as_return_value() + { + var command = new CreateTodoRequest(Guid.NewGuid().ToString(), "Write docs"); + + await Host.Scenario(x => + { + x.Post.Json(command).ToUrl("/api/todo/create"); + x.StatusCodeShouldBe(204); + }); + + var todo = await Load(command.Id); + + todo.Name.ShouldBe("Write docs"); + } + + [Fact] + public async Task use_store_as_return_value() + { + var command = new CreateTodo2(Guid.NewGuid().ToString(), "Write docs"); + await Host.Scenario(x => + { + x.Post.Json(command).ToUrl("/api/todo/create2"); + x.StatusCodeShouldBe(204); + }); + + var todo = await Load(command.Id); + + todo.Name.ShouldBe("Write docs"); + } + + [Fact] + public async Task use_entity_attribute_with_id() + { + var command = new CreateTodoRequest(Guid.NewGuid().ToString(), "Write docs"); + await Host.InvokeMessageAndWaitAsync(command); + + await Host.Scenario(x => + { + x.Post.Json(new RenameTodo(command.Id, "New name")).ToUrl("/api/todo/update"); + x.StatusCodeShouldBe(204); + }); + + var todo = await Load(command.Id); + todo.Name.ShouldBe("New name"); + } + + [Fact] + public async Task use_entity_attribute_with_entity_id() + { + var command = new CreateTodoRequest(Guid.NewGuid().ToString(), "Write docs"); + await Host.InvokeMessageAndWaitAsync(command); + + await Host.Scenario(x => + { + x.Post.Json(new RenameTodo2(command.Id, "New name2")).ToUrl("/api/todo/update2"); + x.StatusCodeShouldBe(204); + }); + + var todo = await Load(command.Id); + todo.Name.ShouldBe("New name2"); + } + + [Fact] + public async Task use_entity_attribute_with_explicit_id() + { + var command = new CreateTodoRequest(Guid.NewGuid().ToString(), "Write docs"); + await Host.InvokeMessageAndWaitAsync(command); + + await Host.Scenario(x => + { + x.Post.Json(new RenameTodo3(command.Id, "New name3")).ToUrl("/api/todo/update3"); + x.StatusCodeShouldBe(204); + }); + + var todo = await Load(command.Id); + todo.Name.ShouldBe("New name3"); + } + + [Fact] + public async Task use_generic_action_as_insert() + { + var shouldInsert = new MaybeInsertTodo(Guid.NewGuid().ToString(), "Pick up milk", true); + var shouldDoNothing = new MaybeInsertTodo(Guid.NewGuid().ToString(), "Start soup", false); + + await Host.Scenario(x => + { + x.Post.Json(shouldInsert).ToUrl("/api/todo/maybeinsert"); + x.StatusCodeShouldBe(204); + }); + + await Host.Scenario(x => + { + x.Post.Json(shouldDoNothing).ToUrl("/api/todo/maybeinsert"); + x.StatusCodeShouldBe(204); + }); + + (await Load(shouldInsert.Id)).Name.ShouldBe("Pick up milk"); + (await Load(shouldDoNothing.Id)).ShouldBeNull(); + } + + [Fact] + public async Task do_nothing_if_storage_action_is_null() + { + // Just a smoke test + var command = new ReturnNullInsert(); + await Host.Scenario(x => + { + x.Post.Json(command).ToUrl("/api/todo/nullinsert"); + x.StatusCodeShouldBe(204); + }); + } + + [Fact] + public async Task do_nothing_if_generic_storage_action_is_null() + { + // Just a smoke test + var command = new ReturnNullStorageAction(); + await Host.Scenario(x => + { + x.Post.Json(command).ToUrl("/api/todo/nullaction"); + x.StatusCodeShouldBe(204); + }); + } + + [Fact] + public async Task do_not_execute_the_handler_if_the_entity_is_not_found() + { + await Host.Scenario(x => + { + x.Post.Json(new CompleteTodo(Guid.NewGuid().ToString())).ToUrl("/api/todo/complete"); + x.StatusCodeShouldBe(404); + }); + + var todoId = Guid.NewGuid().ToString(); + await Host.InvokeMessageAndWaitAsync(new CreateTodoRequest(todoId, "Write docs")); + + // This should be fine + await Host.Scenario(x => + { + x.Post.Json(new CompleteTodo(todoId)).ToUrl("/api/todo/complete"); + x.StatusCodeShouldBe(204); + }); + + (await Load(todoId)).IsComplete.ShouldBeTrue(); + } + + [Fact] + public async Task handler_not_required_entity_attributes() + { + // This handler will do nothing if the Todo is null + await Host.Scenario(x => + { + x.Post.Json(new MaybeCompleteTodo(Guid.NewGuid().ToString())).ToUrl("/api/todo/maybecomplete"); + x.StatusCodeShouldBe(204); + }); + + var todoId = Guid.NewGuid().ToString(); + + await Host.InvokeMessageAndWaitAsync(new CreateTodoRequest(todoId, "Write docs")); + + // This should be fine + await Host.Scenario(x => + { + x.Post.Json(new MaybeCompleteTodo(todoId)).ToUrl("/api/todo/maybecomplete"); + x.StatusCodeShouldBe(204); + }); + + (await Load(todoId)).IsComplete.ShouldBeTrue(); + } + + [Fact] + public async Task entity_can_be_used_in_before_methods_implied_from_main_handler_method() + { + var todoId = Guid.NewGuid().ToString(); + await Host.InvokeMessageAndWaitAsync(new CreateTodoRequest(todoId, "Write docs")); + + // This should be fine + + await Host.Scenario(x => + { + x.Post.Json(new MarkTaskCompleteWithBeforeUsage(todoId)).ToUrl("/api/todo/maybetaskcompletewithbeforeusage"); + x.StatusCodeShouldBe(204); + }); + + (await Load(todoId)).IsComplete.ShouldBeTrue(); + } + + [Fact] + public async Task can_use_attribute_on_before_methods() + { + ExamineFirstHandler.DidContinue = false; + + // Negative case, Todo does not exist, main handler should NOT have executed + await Host.Scenario(x => + { + x.Post.Json(new ExamineFirst(Guid.NewGuid().ToString())).ToUrl("/api/todo/examinefirst"); + x.StatusCodeShouldBe(404); + }); + + ExamineFirstHandler.DidContinue.ShouldBeFalse(); + + // Positive case, Todo exists + var todoId = Guid.NewGuid().ToString(); + await Host.InvokeMessageAndWaitAsync(new CreateTodoRequest(todoId, "Write docs")); + + await Host.Scenario(x => + { + x.Post.Json(new ExamineFirst(todoId)).ToUrl("/api/todo/examinefirst"); + x.StatusCodeShouldBe(204); + }); + + ExamineFirstHandler.DidContinue.ShouldBeTrue(); + + + } + + [Fact] + public async Task fall_down_to_route_argument_if_no_request_body() + { + var todoId = Guid.NewGuid().ToString(); + await Host.InvokeMessageAndWaitAsync(new CreateTodoRequest(todoId, "Write docs")); + + // Found + var result = await Host.Scenario(x => + { + x.Get.Url("/api/todo/" + todoId); + }); + + result.ReadAsJson().Id.ShouldBe(todoId); + + // Miss, should be 404 + await Host.Scenario(x => + { + x.Get.Url("/api/todo/nonexistent"); + x.StatusCodeShouldBe(404); + }); + + } +} \ No newline at end of file diff --git a/src/Http/Wolverine.Http/CodeGen/HttpChainParameterAttributeStrategy.cs b/src/Http/Wolverine.Http/CodeGen/HttpChainParameterAttributeStrategy.cs index 3adc1d69f..36a1f53b6 100644 --- a/src/Http/Wolverine.Http/CodeGen/HttpChainParameterAttributeStrategy.cs +++ b/src/Http/Wolverine.Http/CodeGen/HttpChainParameterAttributeStrategy.cs @@ -1,6 +1,7 @@ using System.Reflection; using JasperFx.CodeGeneration.Model; using JasperFx.Core.Reflection; +using Wolverine.Attributes; using Wolverine.Runtime; namespace Wolverine.Http.CodeGen; @@ -15,6 +16,12 @@ public bool TryMatch(HttpChain chain, IServiceContainer container, ParameterInfo return true; } + if (parameter.TryGetAttribute(out var att2)) + { + variable = att2.Modify(chain, parameter, container, container.GetInstance().CodeGeneration); + return true; + } + variable = default; return false; } diff --git a/src/Http/Wolverine.Http/CodeGen/QueryStringHandling.cs b/src/Http/Wolverine.Http/CodeGen/QueryStringHandling.cs index aa4effd93..fc6663207 100644 --- a/src/Http/Wolverine.Http/CodeGen/QueryStringHandling.cs +++ b/src/Http/Wolverine.Http/CodeGen/QueryStringHandling.cs @@ -187,4 +187,4 @@ public bool TryMatch(HttpChain chain, IServiceContainer container, ParameterInfo variable = chain.TryFindOrCreateQuerystringValue(parameter); return variable != null; } -} +} \ No newline at end of file diff --git a/src/Http/Wolverine.Http/CodeGen/RouteHandling.cs b/src/Http/Wolverine.Http/CodeGen/RouteHandling.cs index 967f7264e..2bb6b278f 100644 --- a/src/Http/Wolverine.Http/CodeGen/RouteHandling.cs +++ b/src/Http/Wolverine.Http/CodeGen/RouteHandling.cs @@ -28,11 +28,21 @@ internal class ParsedRouteArgumentFrame : SyncFrame { public ParsedRouteArgumentFrame(ParameterInfo parameter) { + if (parameter.ParameterType == typeof(string)) + { + throw new ArgumentOutOfRangeException(nameof(parameter), "Cannot be used with string parameters"); + } + Variable = new Variable(parameter.ParameterType, parameter.Name!, this); } public ParsedRouteArgumentFrame(Type variableType, string parameterName) { + if (variableType == typeof(string)) + { + throw new ArgumentOutOfRangeException(nameof(variableType), "Cannot be used with string parameters"); + } + Variable = new Variable(variableType, parameterName, this); } diff --git a/src/Http/Wolverine.Http/HttpChain.ApiDescription.cs b/src/Http/Wolverine.Http/HttpChain.ApiDescription.cs index 59b780853..84cc01d3c 100644 --- a/src/Http/Wolverine.Http/HttpChain.ApiDescription.cs +++ b/src/Http/Wolverine.Http/HttpChain.ApiDescription.cs @@ -1,6 +1,8 @@ using System.Collections.Immutable; using System.Reflection; using JasperFx.CodeGeneration.Frames; +using JasperFx.CodeGeneration.Model; +using JasperFx.Core; using JasperFx.Core.Reflection; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http.Metadata; @@ -13,6 +15,8 @@ using Microsoft.AspNetCore.Mvc.ModelBinding.Metadata; using Microsoft.AspNetCore.Routing; using Microsoft.AspNetCore.Routing.Patterns; +using Wolverine.Attributes; +using Wolverine.Codegen; namespace Wolverine.Http; @@ -132,6 +136,36 @@ public override void UseForResponse(MethodCall methodCall) ResourceVariable = methodCall.ReturnVariable; } + public override bool TryFindVariable(string valueName, ValueSource source, Type valueType, out Variable variable) + { + if ((source == ValueSource.RouteValue || source == ValueSource.Anything) && FindRouteVariable(valueType, valueName, out variable)) + { + return true; + } + + if (HasRequestType) + { + var requestType = InputType(); + var member = requestType.GetProperties() + .FirstOrDefault(x => x.Name.EqualsIgnoreCase(valueName) && x.PropertyType == valueType) + ?? (MemberInfo)requestType.GetFields() + .FirstOrDefault(x => x.Name.EqualsIgnoreCase(valueName) && x.FieldType == valueType); + + if (member != null) + { + if (RequestBodyVariable == null) + throw new InvalidOperationException( + "Requesting member access to the request body, but the request body is not (yet) set."); + + variable = new MemberAccessVariable(RequestBodyVariable, member); + return true; + } + } + + variable = default!; + return false; + } + private sealed record NormalizedResponseMetadata(int StatusCode, Type? Type, IEnumerable ContentTypes) { // if an attribute doesn't specific the content type, conform with OpenAPI internals and infer. diff --git a/src/Http/Wolverine.Http/HttpChain.cs b/src/Http/Wolverine.Http/HttpChain.cs index 8693b4ca2..76ffd1bdb 100644 --- a/src/Http/Wolverine.Http/HttpChain.cs +++ b/src/Http/Wolverine.Http/HttpChain.cs @@ -18,6 +18,7 @@ using Wolverine.Configuration; using Wolverine.Http.CodeGen; using Wolverine.Http.Metadata; +using Wolverine.Http.Policies; using Wolverine.Runtime; using ServiceContainer = Wolverine.Runtime.ServiceContainer; @@ -272,6 +273,11 @@ public override bool HasAttribute() return HasRequestType ? RequestType : null; } + public override Frame[] AddStopConditionIfNull(Variable variable) + { + return [new SetStatusCodeAndReturnIfEntityIsNullFrame(variable)]; + } + public override string ToString() { return _fileName!; @@ -411,14 +417,14 @@ public bool FindRouteVariable(ParameterInfo parameter, [NotNullWhen(true)]out Va public bool FindRouteVariable(Type variableType, string routeOrParameterName, [NotNullWhen(true)]out Variable? variable) { var matched = - _routeVariables.FirstOrDefault(x => x.VariableType == variableType && x.Usage == routeOrParameterName); + _routeVariables.FirstOrDefault(x => x.VariableType == variableType && x.Usage.EqualsIgnoreCase(routeOrParameterName)); if (matched is not null) { variable = matched; return true; } - var matches = RoutePattern!.Parameters.Any(x => x.Name == routeOrParameterName); + var matches = RoutePattern!.Parameters.Any(x => x.Name.EqualsIgnoreCase(routeOrParameterName)); if (matches) { if (variableType == typeof(string)) diff --git a/src/Http/Wolverine.Http/Policies/RequiredEntityPolicy.cs b/src/Http/Wolverine.Http/Policies/RequiredEntityPolicy.cs index a8cfbda82..27c0924a0 100644 --- a/src/Http/Wolverine.Http/Policies/RequiredEntityPolicy.cs +++ b/src/Http/Wolverine.Http/Policies/RequiredEntityPolicy.cs @@ -35,13 +35,19 @@ public class SetStatusCodeAndReturnIfEntityIsNullFrame : SyncFrame { private readonly Type _entityType; private Variable _httpResponse; - private Variable _entity; + private Variable? _entity; public SetStatusCodeAndReturnIfEntityIsNullFrame(Type entityType) { _entityType = entityType; } + public SetStatusCodeAndReturnIfEntityIsNullFrame(Variable entity) + { + _entity = entity; + _entityType = entity.VariableType; + } + public override void GenerateCode(GeneratedMethod method, ISourceWriter writer) { writer.WriteComment("404 if this required object is null"); @@ -63,7 +69,7 @@ public override void GenerateCode(GeneratedMethod method, ISourceWriter writer) public override IEnumerable FindVariables(IMethodVariables chain) { - _entity = chain.FindVariable(_entityType); + _entity ??= chain.FindVariable(_entityType); yield return _entity; _httpResponse = chain.FindVariable(typeof(HttpResponse)); diff --git a/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/AfterMessage1Handler533023927.cs b/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/AfterMessage1Handler533023927.cs new file mode 100644 index 000000000..ba9609b4e --- /dev/null +++ b/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/AfterMessage1Handler533023927.cs @@ -0,0 +1,29 @@ +// +#pragma warning disable + +namespace Internal.Generated.WolverineHandlers +{ + // START: AfterMessage1Handler533023927 + public class AfterMessage1Handler533023927 : Wolverine.Runtime.Handlers.MessageHandler + { + + + public override System.Threading.Tasks.Task HandleAsync(Wolverine.Runtime.MessageContext context, System.Threading.CancellationToken cancellation) + { + // The actual message body + var afterMessage1 = (WolverineWebApi.AfterMessage1)context.Envelope.Message; + + + // The actual message execution + WolverineWebApi.MiddlewareMessageHandler.Handle(afterMessage1); + + return System.Threading.Tasks.Task.CompletedTask; + } + + } + + // END: AfterMessage1Handler533023927 + + +} + diff --git a/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/BeforeMessage1Handler784498762.cs b/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/BeforeMessage1Handler784498762.cs new file mode 100644 index 000000000..8cdd4e825 --- /dev/null +++ b/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/BeforeMessage1Handler784498762.cs @@ -0,0 +1,29 @@ +// +#pragma warning disable + +namespace Internal.Generated.WolverineHandlers +{ + // START: BeforeMessage1Handler784498762 + public class BeforeMessage1Handler784498762 : Wolverine.Runtime.Handlers.MessageHandler + { + + + public override System.Threading.Tasks.Task HandleAsync(Wolverine.Runtime.MessageContext context, System.Threading.CancellationToken cancellation) + { + // The actual message body + var beforeMessage1 = (WolverineWebApi.BeforeMessage1)context.Envelope.Message; + + + // The actual message execution + WolverineWebApi.MiddlewareMessageHandler.Handle(beforeMessage1); + + return System.Threading.Tasks.Task.CompletedTask; + } + + } + + // END: BeforeMessage1Handler784498762 + + +} + diff --git a/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/CreateTodoRequestHandler482446425.cs b/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/CreateTodoRequestHandler482446425.cs new file mode 100644 index 000000000..24446493b --- /dev/null +++ b/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/CreateTodoRequestHandler482446425.cs @@ -0,0 +1,53 @@ +// +#pragma warning disable +using Wolverine.Marten.Publishing; + +namespace Internal.Generated.WolverineHandlers +{ + // START: CreateTodoRequestHandler482446425 + public class CreateTodoRequestHandler482446425 : Wolverine.Runtime.Handlers.MessageHandler + { + private readonly Wolverine.Marten.Publishing.OutboxedSessionFactory _outboxedSessionFactory; + + public CreateTodoRequestHandler482446425(Wolverine.Marten.Publishing.OutboxedSessionFactory outboxedSessionFactory) + { + _outboxedSessionFactory = outboxedSessionFactory; + } + + + + public override async System.Threading.Tasks.Task HandleAsync(Wolverine.Runtime.MessageContext context, System.Threading.CancellationToken cancellation) + { + // Building the Marten session + await using var documentSession = _outboxedSessionFactory.OpenSession(context); + // The actual message body + var createTodoRequest = (WolverineWebApi.Todos.CreateTodoRequest)context.Envelope.Message; + + + // The actual message execution + var outgoing1 = WolverineWebApi.Todos.TodoHandler.Handle(createTodoRequest); + + if (outgoing1 != null) + { + + // Register the document operation with the current session + documentSession.Insert(outgoing1.Entity); + } + + + // Save all pending changes to this Marten session + await documentSession.SaveChangesAsync(cancellation).ConfigureAwait(false); + + + // Have to flush outgoing messages just in case Marten did nothing because of https://github.com/JasperFx/wolverine/issues/536 + await context.FlushOutgoingMessagesAsync().ConfigureAwait(false); + + } + + } + + // END: CreateTodoRequestHandler482446425 + + +} + diff --git a/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/CustomRequestHandler1116913013.cs b/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/CustomRequestHandler1116913013.cs new file mode 100644 index 000000000..8e8595a12 --- /dev/null +++ b/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/CustomRequestHandler1116913013.cs @@ -0,0 +1,32 @@ +// +#pragma warning disable + +namespace Internal.Generated.WolverineHandlers +{ + // START: CustomRequestHandler1116913013 + public class CustomRequestHandler1116913013 : Wolverine.Runtime.Handlers.MessageHandler + { + + + public override async System.Threading.Tasks.Task HandleAsync(Wolverine.Runtime.MessageContext context, System.Threading.CancellationToken cancellation) + { + // The actual message body + var customRequest = (WolverineWebApi.CustomRequest)context.Envelope.Message; + + + // The actual message execution + var outgoing1 = WolverineWebApi.MessageHandler.Handle(customRequest); + + + // Outgoing, cascaded message + await context.EnqueueCascadingAsync(outgoing1).ConfigureAwait(false); + + } + + } + + // END: CustomRequestHandler1116913013 + + +} + diff --git a/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/DELETE_api_trainer.cs b/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/DELETE_api_trainer.cs new file mode 100644 index 000000000..af6c46a2a --- /dev/null +++ b/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/DELETE_api_trainer.cs @@ -0,0 +1,56 @@ +// +#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: DELETE_api_trainer + public class DELETE_api_trainer : Wolverine.Http.HttpHandler + { + private readonly Wolverine.Http.WolverineHttpOptions _wolverineHttpOptions; + private readonly Wolverine.Runtime.IWolverineRuntime _wolverineRuntime; + private readonly Wolverine.Marten.Publishing.OutboxedSessionFactory _outboxedSessionFactory; + + public DELETE_api_trainer(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); + var userId = WolverineWebApi.UserIdMiddleware.LoadAsync(httpContext); + var trainerDelete = new WolverineWebApi.TrainerDelete(); + + // The actual HTTP request handler execution + var result = await trainerDelete.Delete(userId, documentSession, httpContext.RequestAborted).ConfigureAwait(false); + + + // 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: DELETE_api_trainer + + +} + diff --git a/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/DELETE_optional_result.cs b/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/DELETE_optional_result.cs new file mode 100644 index 000000000..a18548e9a --- /dev/null +++ b/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/DELETE_optional_result.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: DELETE_optional_result + public class DELETE_optional_result : Wolverine.Http.HttpHandler + { + private readonly Wolverine.Http.WolverineHttpOptions _wolverineHttpOptions; + + public DELETE_optional_result(Wolverine.Http.WolverineHttpOptions wolverineHttpOptions) : base(wolverineHttpOptions) + { + _wolverineHttpOptions = wolverineHttpOptions; + } + + + + public override async System.Threading.Tasks.Task Handle(Microsoft.AspNetCore.Http.HttpContext httpContext) + { + // Reading the request body via JSON deserialization + var (cmd, jsonContinue) = await ReadJsonAsync(httpContext); + if (jsonContinue == Wolverine.HandlerContinuation.Stop) return; + var user = WolverineWebApi.Validation.ValidatedCompoundEndpoint2.Load(cmd); + var result1 = WolverineWebApi.Validation.ValidatedCompoundEndpoint2.Validate(user); + // Evaluate whether or not the execution should be stopped based on the IResult value + if (result1 != null && !(result1 is Wolverine.Http.WolverineContinue)) + { + await result1.ExecuteAsync(httpContext).ConfigureAwait(false); + return; + } + + + + // The actual HTTP request handler execution + var result_of_Handle = WolverineWebApi.Validation.ValidatedCompoundEndpoint2.Handle(cmd, user); + + await WriteString(httpContext, result_of_Handle); + } + + } + + // END: DELETE_optional_result + + +} + diff --git a/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/DELETE_validate_user_compound.cs b/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/DELETE_validate_user_compound.cs new file mode 100644 index 000000000..629e6b516 --- /dev/null +++ b/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/DELETE_validate_user_compound.cs @@ -0,0 +1,68 @@ +// +#pragma warning disable +using FluentValidation; +using Microsoft.AspNetCore.Routing; +using System; +using System.Linq; +using Wolverine.Http; +using Wolverine.Http.FluentValidation; + +namespace Internal.Generated.WolverineHandlers +{ + // START: DELETE_validate_user_compound + public class DELETE_validate_user_compound : Wolverine.Http.HttpHandler + { + private readonly Wolverine.Http.WolverineHttpOptions _wolverineHttpOptions; + private readonly Wolverine.Http.FluentValidation.IProblemDetailSource _problemDetailSource; + private readonly FluentValidation.IValidator _validator; + + public DELETE_validate_user_compound(Wolverine.Http.WolverineHttpOptions wolverineHttpOptions, Wolverine.Http.FluentValidation.IProblemDetailSource problemDetailSource, FluentValidation.IValidator validator) : base(wolverineHttpOptions) + { + _wolverineHttpOptions = wolverineHttpOptions; + _problemDetailSource = problemDetailSource; + _validator = validator; + } + + + + public override async System.Threading.Tasks.Task Handle(Microsoft.AspNetCore.Http.HttpContext httpContext) + { + // Reading the request body via JSON deserialization + var (cmd, jsonContinue) = await ReadJsonAsync(httpContext); + if (jsonContinue == Wolverine.HandlerContinuation.Stop) return; + + // Execute FluentValidation validators + var result1 = await Wolverine.Http.FluentValidation.Internals.FluentValidationHttpExecutor.ExecuteOne(_validator, _problemDetailSource, cmd).ConfigureAwait(false); + + // Evaluate whether or not the execution should be stopped based on the IResult value + if (result1 != null && !(result1 is Wolverine.Http.WolverineContinue)) + { + await result1.ExecuteAsync(httpContext).ConfigureAwait(false); + return; + } + + + var user = WolverineWebApi.Validation.ValidatedCompoundEndpoint.Load(cmd); + var result2 = WolverineWebApi.Validation.ValidatedCompoundEndpoint.Validate(user); + // Evaluate whether or not the execution should be stopped based on the IResult value + if (result2 != null && !(result2 is Wolverine.Http.WolverineContinue)) + { + await result2.ExecuteAsync(httpContext).ConfigureAwait(false); + return; + } + + + + // The actual HTTP request handler execution + var result_of_Handle = WolverineWebApi.Validation.ValidatedCompoundEndpoint.Handle(cmd, user); + + await WriteString(httpContext, result_of_Handle); + } + + } + + // END: DELETE_validate_user_compound + + +} + diff --git a/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/DataHandler620835457.cs b/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/DataHandler620835457.cs new file mode 100644 index 000000000..9e0e701de --- /dev/null +++ b/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/DataHandler620835457.cs @@ -0,0 +1,30 @@ +// +#pragma warning disable + +namespace Internal.Generated.WolverineHandlers +{ + // START: DataHandler620835457 + public class DataHandler620835457 : Wolverine.Runtime.Handlers.MessageHandler + { + + + public override System.Threading.Tasks.Task HandleAsync(Wolverine.Runtime.MessageContext context, System.Threading.CancellationToken cancellation) + { + // The actual message body + var data = (WolverineWebApi.Data)context.Envelope.Message; + + var dataHandler = new WolverineWebApi.DataHandler(); + + // The actual message execution + dataHandler.Handle(data); + + return System.Threading.Tasks.Task.CompletedTask; + } + + } + + // END: DataHandler620835457 + + +} + diff --git a/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/GET_age_age.cs b/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/GET_age_age.cs new file mode 100644 index 000000000..0d0d849db --- /dev/null +++ b/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/GET_age_age.cs @@ -0,0 +1,45 @@ +// +#pragma warning disable +using Microsoft.AspNetCore.Routing; +using System; +using System.Linq; +using Wolverine.Http; + +namespace Internal.Generated.WolverineHandlers +{ + // START: GET_age_age + public class GET_age_age : Wolverine.Http.HttpHandler + { + private readonly Wolverine.Http.WolverineHttpOptions _wolverineHttpOptions; + + public GET_age_age(Wolverine.Http.WolverineHttpOptions wolverineHttpOptions) : base(wolverineHttpOptions) + { + _wolverineHttpOptions = wolverineHttpOptions; + } + + + + public override async System.Threading.Tasks.Task Handle(Microsoft.AspNetCore.Http.HttpContext httpContext) + { + if (!int.TryParse((string)httpContext.GetRouteValue("age"), out var age)) + { + httpContext.Response.StatusCode = 404; + return; + } + + + // Just saying hello in the code! Also testing the usage of attributes to customize endpoints + + // The actual HTTP request handler execution + var result_of_IntRouteArgument = WolverineWebApi.TestEndpoints.IntRouteArgument(age); + + await WriteString(httpContext, result_of_IntRouteArgument); + } + + } + + // END: GET_age_age + + +} + diff --git a/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/GET_api_myapp_registration_price.cs b/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/GET_api_myapp_registration_price.cs new file mode 100644 index 000000000..43d4d83e3 --- /dev/null +++ b/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/GET_api_myapp_registration_price.cs @@ -0,0 +1,40 @@ +// +#pragma warning disable +using Microsoft.AspNetCore.Routing; +using System; +using System.Linq; +using Wolverine.Http; + +namespace Internal.Generated.WolverineHandlers +{ + // START: GET_api_myapp_registration_price + public class GET_api_myapp_registration_price : Wolverine.Http.HttpHandler + { + private readonly Wolverine.Http.WolverineHttpOptions _wolverineHttpOptions; + + public GET_api_myapp_registration_price(Wolverine.Http.WolverineHttpOptions wolverineHttpOptions) : base(wolverineHttpOptions) + { + _wolverineHttpOptions = wolverineHttpOptions; + } + + + + public override async System.Threading.Tasks.Task Handle(Microsoft.AspNetCore.Http.HttpContext httpContext) + { + int numberOfMembers = default; + int.TryParse(httpContext.Request.Query["numberOfMembers"], System.Globalization.CultureInfo.InvariantCulture, out numberOfMembers); + + // The actual HTTP request handler execution + var decimalValue_response = WolverineWebApi.Bugs.MyAppLandingEndpoint.GetRegistrationPrice(numberOfMembers); + + // Writing the response body to JSON because this was the first 'return variable' in the method signature + await WriteJsonAsync(httpContext, decimalValue_response); + } + + } + + // END: GET_api_myapp_registration_price + + +} + diff --git a/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/GET_api_todo_id.cs b/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/GET_api_todo_id.cs new file mode 100644 index 000000000..13f4f4282 --- /dev/null +++ b/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/GET_api_todo_id.cs @@ -0,0 +1,58 @@ +// +#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_api_todo_id + public class GET_api_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_api_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) + { + var messageContext = new Wolverine.Runtime.MessageContext(_wolverineRuntime); + // Building the Marten session + await using var documentSession = _outboxedSessionFactory.OpenSession(messageContext); + var id = (string)httpContext.GetRouteValue("id"); + + // Try to load the existing saga document + var todo2 = await documentSession.LoadAsync(id, httpContext.RequestAborted).ConfigureAwait(false); + // 404 if this required object is null + if (todo2 == null) + { + httpContext.Response.StatusCode = 404; + return; + } + + + // The actual HTTP request handler execution + var todo2_response = WolverineWebApi.Todos.TodoHandler.Get(todo2); + + // Writing the response body to JSON because this was the first 'return variable' in the method signature + await WriteJsonAsync(httpContext, todo2_response); + } + + } + + // END: GET_api_todo_id + + +} + diff --git a/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/GET_correlation.cs b/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/GET_correlation.cs new file mode 100644 index 000000000..2cbfc3e53 --- /dev/null +++ b/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/GET_correlation.cs @@ -0,0 +1,42 @@ +// +#pragma warning disable +using Microsoft.AspNetCore.Routing; +using System; +using System.Linq; +using Wolverine.Http; +using Wolverine.Runtime; + +namespace Internal.Generated.WolverineHandlers +{ + // START: GET_correlation + public class GET_correlation : Wolverine.Http.HttpHandler + { + private readonly Wolverine.Http.WolverineHttpOptions _wolverineHttpOptions; + private readonly Wolverine.Runtime.IWolverineRuntime _wolverineRuntime; + + public GET_correlation(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) + { + var messageContext = new Wolverine.Runtime.MessageContext(_wolverineRuntime); + Wolverine.Http.Runtime.RequestIdMiddleware.Apply(httpContext, messageContext); + + // The actual HTTP request handler execution + var result_of_GetCorrelation = WolverineWebApi.TracingEndpoint.GetCorrelation(messageContext); + + await WriteString(httpContext, result_of_GetCorrelation); + } + + } + + // END: GET_correlation + + +} + diff --git a/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/GET_data_id.cs b/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/GET_data_id.cs new file mode 100644 index 000000000..e2755b318 --- /dev/null +++ b/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/GET_data_id.cs @@ -0,0 +1,64 @@ +// +#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_data_id + public class GET_data_id : Wolverine.Http.HttpHandler + { + private readonly Wolverine.Http.WolverineHttpOptions _wolverineHttpOptions; + private readonly Wolverine.Runtime.IWolverineRuntime _wolverineRuntime; + private readonly Wolverine.Marten.Publishing.OutboxedSessionFactory _outboxedSessionFactory; + + public GET_data_id(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); + if (!System.Guid.TryParse((string)httpContext.GetRouteValue("id"), out var id)) + { + httpContext.Response.StatusCode = 404; + return; + } + + + // Just saying hello in the code! Also testing the usage of attributes to customize endpoints + var serviceEndpoints = new WolverineWebApi.ServiceEndpoints(); + + // The actual HTTP request handler execution + var data_response = await serviceEndpoints.GetData(id, documentSession).ConfigureAwait(false); + + + // 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); + + // Writing the response body to JSON because this was the first 'return variable' in the method signature + await WriteJsonAsync(httpContext, data_response); + } + + } + + // END: GET_data_id + + +} + diff --git a/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/GET_discovered.cs b/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/GET_discovered.cs new file mode 100644 index 000000000..a2411a491 --- /dev/null +++ b/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/GET_discovered.cs @@ -0,0 +1,37 @@ +// +#pragma warning disable +using Microsoft.AspNetCore.Routing; +using System; +using System.Linq; +using Wolverine.Http; + +namespace Internal.Generated.WolverineHandlers +{ + // START: GET_discovered + public class GET_discovered : Wolverine.Http.HttpHandler + { + private readonly Wolverine.Http.WolverineHttpOptions _wolverineHttpOptions; + + public GET_discovered(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_Get = WolverineWebApi.DiscoverMe.Get(); + + await WriteString(httpContext, result_of_Get); + } + + } + + // END: GET_discovered + + +} + diff --git a/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/GET_document_required_document_attribute_only_id.cs b/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/GET_document_required_document_attribute_only_id.cs new file mode 100644 index 000000000..afaf15c9e --- /dev/null +++ b/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/GET_document_required_document_attribute_only_id.cs @@ -0,0 +1,79 @@ +// +#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_document_required_document_attribute_only_id + public class GET_document_required_document_attribute_only_id : Wolverine.Http.HttpHandler + { + private readonly Wolverine.Http.WolverineHttpOptions _wolverineHttpOptions; + private readonly Wolverine.Runtime.IWolverineRuntime _wolverineRuntime; + private readonly Wolverine.Marten.Publishing.OutboxedSessionFactory _outboxedSessionFactory; + + public GET_document_required_document_attribute_only_id(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); + if (!System.Guid.TryParse((string)httpContext.GetRouteValue("id"), out var id)) + { + httpContext.Response.StatusCode = 404; + return; + } + + + var invoice = await documentSession.LoadAsync(id, httpContext.RequestAborted).ConfigureAwait(false); + // 404 if this required object is null + if (invoice == null) + { + httpContext.Response.StatusCode = 404; + return; + } + + var problemDetails1 = WolverineWebApi.Marten.DocumentRequiredEndpoint.Load(invoice); + // Evaluate whether the processing should stop if there are any problems + if (!(ReferenceEquals(problemDetails1, Wolverine.Http.WolverineContinue.NoProblems))) + { + await WriteProblems(problemDetails1, httpContext).ConfigureAwait(false); + return; + } + + + + // The actual HTTP request handler execution + var invoice_response = WolverineWebApi.Marten.DocumentRequiredEndpoint.DocumentAttributeOnly(invoice); + + + // 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); + + // Writing the response body to JSON because this was the first 'return variable' in the method signature + await WriteJsonAsync(httpContext, invoice_response); + } + + } + + // END: GET_document_required_document_attribute_only_id + + +} + diff --git a/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/GET_document_required_separate_attributes_id.cs b/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/GET_document_required_separate_attributes_id.cs new file mode 100644 index 000000000..539248eba --- /dev/null +++ b/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/GET_document_required_separate_attributes_id.cs @@ -0,0 +1,79 @@ +// +#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_document_required_separate_attributes_id + public class GET_document_required_separate_attributes_id : Wolverine.Http.HttpHandler + { + private readonly Wolverine.Http.WolverineHttpOptions _wolverineHttpOptions; + private readonly Wolverine.Runtime.IWolverineRuntime _wolverineRuntime; + private readonly Wolverine.Marten.Publishing.OutboxedSessionFactory _outboxedSessionFactory; + + public GET_document_required_separate_attributes_id(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) + { + if (!System.Guid.TryParse((string)httpContext.GetRouteValue("id"), out var id)) + { + httpContext.Response.StatusCode = 404; + return; + } + + + var messageContext = new Wolverine.Runtime.MessageContext(_wolverineRuntime); + // Building the Marten session + await using var documentSession = _outboxedSessionFactory.OpenSession(messageContext); + var invoice = await documentSession.LoadAsync(id, httpContext.RequestAborted).ConfigureAwait(false); + var problemDetails1 = WolverineWebApi.Marten.DocumentRequiredEndpoint.Load(invoice); + // Evaluate whether the processing should stop if there are any problems + if (!(ReferenceEquals(problemDetails1, Wolverine.Http.WolverineContinue.NoProblems))) + { + await WriteProblems(problemDetails1, httpContext).ConfigureAwait(false); + return; + } + + + // 404 if this required object is null + if (invoice == null) + { + httpContext.Response.StatusCode = 404; + return; + } + + + // The actual HTTP request handler execution + var invoice_response = WolverineWebApi.Marten.DocumentRequiredEndpoint.SeparateAttributes(invoice); + + + // 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); + + // Writing the response body to JSON because this was the first 'return variable' in the method signature + await WriteJsonAsync(httpContext, invoice_response); + } + + } + + // END: GET_document_required_separate_attributes_id + + +} + diff --git a/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/GET_enum_direction.cs b/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/GET_enum_direction.cs new file mode 100644 index 000000000..f1f168d7f --- /dev/null +++ b/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/GET_enum_direction.cs @@ -0,0 +1,45 @@ +// +#pragma warning disable +using Microsoft.AspNetCore.Routing; +using System; +using System.Linq; +using Wolverine.Http; + +namespace Internal.Generated.WolverineHandlers +{ + // START: GET_enum_direction + public class GET_enum_direction : Wolverine.Http.HttpHandler + { + private readonly Wolverine.Http.WolverineHttpOptions _wolverineHttpOptions; + + public GET_enum_direction(Wolverine.Http.WolverineHttpOptions wolverineHttpOptions) : base(wolverineHttpOptions) + { + _wolverineHttpOptions = wolverineHttpOptions; + } + + + + public override async System.Threading.Tasks.Task Handle(Microsoft.AspNetCore.Http.HttpContext httpContext) + { + if (!WolverineWebApi.Direction.TryParse((string)httpContext.GetRouteValue("direction"), true, out WolverineWebApi.Direction direction)) + { + httpContext.Response.StatusCode = 404; + return; + } + + + var fakeEndpoint = new WolverineWebApi.FakeEndpoint(); + + // The actual HTTP request handler execution + var result_of_ReadEnumArgument = fakeEndpoint.ReadEnumArgument(direction); + + await WriteString(httpContext, result_of_ReadEnumArgument); + } + + } + + // END: GET_enum_direction + + +} + diff --git a/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/GET_headers_accepts.cs b/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/GET_headers_accepts.cs new file mode 100644 index 000000000..3aad6da38 --- /dev/null +++ b/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/GET_headers_accepts.cs @@ -0,0 +1,43 @@ +// +#pragma warning disable +using Microsoft.AspNetCore.Routing; +using System; +using System.Linq; +using Wolverine.Http; + +namespace Internal.Generated.WolverineHandlers +{ + // START: GET_headers_accepts + public class GET_headers_accepts : Wolverine.Http.HttpHandler + { + private readonly Wolverine.Http.WolverineHttpOptions _wolverineHttpOptions; + + public GET_headers_accepts(Wolverine.Http.WolverineHttpOptions wolverineHttpOptions) : base(wolverineHttpOptions) + { + _wolverineHttpOptions = wolverineHttpOptions; + } + + + + public override async System.Threading.Tasks.Task Handle(Microsoft.AspNetCore.Http.HttpContext httpContext) + { + // Retrieve header value from the request + var accepts = ReadSingleHeaderValue(httpContext, "accepts"); + // Retrieve header value from the request + var day = ReadSingleHeaderValue(httpContext, "x-day"); + WolverineWebApi.HeaderUsingEndpoint.Before(day); + var headerUsingEndpoint = new WolverineWebApi.HeaderUsingEndpoint(); + + // The actual HTTP request handler execution + var result_of_GetETag = headerUsingEndpoint.GetETag(accepts); + + await WriteString(httpContext, result_of_GetETag); + } + + } + + // END: GET_headers_accepts + + +} + diff --git a/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/GET_headers_int.cs b/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/GET_headers_int.cs new file mode 100644 index 000000000..3bbb223a2 --- /dev/null +++ b/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/GET_headers_int.cs @@ -0,0 +1,43 @@ +// +#pragma warning disable +using Microsoft.AspNetCore.Routing; +using System; +using System.Linq; +using Wolverine.Http; + +namespace Internal.Generated.WolverineHandlers +{ + // START: GET_headers_int + public class GET_headers_int : Wolverine.Http.HttpHandler + { + private readonly Wolverine.Http.WolverineHttpOptions _wolverineHttpOptions; + + public GET_headers_int(Wolverine.Http.WolverineHttpOptions wolverineHttpOptions) : base(wolverineHttpOptions) + { + _wolverineHttpOptions = wolverineHttpOptions; + } + + + + public override async System.Threading.Tasks.Task Handle(Microsoft.AspNetCore.Http.HttpContext httpContext) + { + int number = default; + int.TryParse(ReadSingleHeaderValue(httpContext, "x-wolverine"), out number); + // Retrieve header value from the request + var day = ReadSingleHeaderValue(httpContext, "x-day"); + WolverineWebApi.HeaderUsingEndpoint.Before(day); + var headerUsingEndpoint = new WolverineWebApi.HeaderUsingEndpoint(); + + // The actual HTTP request handler execution + var result_of_Get = headerUsingEndpoint.Get(number); + + await WriteString(httpContext, result_of_Get); + } + + } + + // END: GET_headers_int + + +} + diff --git a/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/GET_headers_simple.cs b/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/GET_headers_simple.cs new file mode 100644 index 000000000..5fcbbf1b5 --- /dev/null +++ b/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/GET_headers_simple.cs @@ -0,0 +1,43 @@ +// +#pragma warning disable +using Microsoft.AspNetCore.Routing; +using System; +using System.Linq; +using Wolverine.Http; + +namespace Internal.Generated.WolverineHandlers +{ + // START: GET_headers_simple + public class GET_headers_simple : Wolverine.Http.HttpHandler + { + private readonly Wolverine.Http.WolverineHttpOptions _wolverineHttpOptions; + + public GET_headers_simple(Wolverine.Http.WolverineHttpOptions wolverineHttpOptions) : base(wolverineHttpOptions) + { + _wolverineHttpOptions = wolverineHttpOptions; + } + + + + public override async System.Threading.Tasks.Task Handle(Microsoft.AspNetCore.Http.HttpContext httpContext) + { + // Retrieve header value from the request + var name = ReadSingleHeaderValue(httpContext, "x-wolverine"); + // Retrieve header value from the request + var day = ReadSingleHeaderValue(httpContext, "x-day"); + WolverineWebApi.HeaderUsingEndpoint.Before(day); + var headerUsingEndpoint = new WolverineWebApi.HeaderUsingEndpoint(); + + // The actual HTTP request handler execution + var result_of_Get = headerUsingEndpoint.Get(name); + + await WriteString(httpContext, result_of_Get); + } + + } + + // END: GET_headers_simple + + +} + diff --git a/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/GET_hello.cs b/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/GET_hello.cs new file mode 100644 index 000000000..987d91b87 --- /dev/null +++ b/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/GET_hello.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_hello + public class GET_hello : Wolverine.Http.HttpHandler + { + private readonly Wolverine.Http.WolverineHttpOptions _wolverineHttpOptions; + + public GET_hello(Wolverine.Http.WolverineHttpOptions wolverineHttpOptions) : base(wolverineHttpOptions) + { + _wolverineHttpOptions = wolverineHttpOptions; + } + + + + public override async System.Threading.Tasks.Task Handle(Microsoft.AspNetCore.Http.HttpContext httpContext) + { + // Just saying hello in the code! Also testing the usage of attributes to customize endpoints + + // The actual HTTP request handler execution + var result_of_Speak = WolverineWebApi.TestEndpoints.Speak(); + + await WriteString(httpContext, result_of_Speak); + } + + } + + // END: GET_hello + + +} + diff --git a/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/GET_http_context.cs b/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/GET_http_context.cs new file mode 100644 index 000000000..44cdafa4a --- /dev/null +++ b/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/GET_http_context.cs @@ -0,0 +1,40 @@ +// +#pragma warning disable +using Microsoft.AspNetCore.Routing; +using System; +using System.Linq; +using Wolverine.Http; + +namespace Internal.Generated.WolverineHandlers +{ + // START: GET_http_context + public class GET_http_context : Wolverine.Http.HttpHandler + { + private readonly Wolverine.Http.WolverineHttpOptions _wolverineHttpOptions; + + public GET_http_context(Wolverine.Http.WolverineHttpOptions wolverineHttpOptions) : base(wolverineHttpOptions) + { + _wolverineHttpOptions = wolverineHttpOptions; + } + + + + public override System.Threading.Tasks.Task Handle(Microsoft.AspNetCore.Http.HttpContext httpContext) + { + var httpContextEndpoints = new WolverineWebApi.HttpContextEndpoints(); + + // The actual HTTP request handler execution + httpContextEndpoints.UseHttpContext(httpContext); + + // Wolverine automatically sets the status code to 204 for empty responses + if (!httpContext.Response.HasStarted) httpContext.Response.StatusCode = 204; + return System.Threading.Tasks.Task.CompletedTask; + } + + } + + // END: GET_http_context + + +} + diff --git a/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/GET_http_identifier.cs b/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/GET_http_identifier.cs new file mode 100644 index 000000000..944bf1e44 --- /dev/null +++ b/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/GET_http_identifier.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_http_identifier + public class GET_http_identifier : Wolverine.Http.HttpHandler + { + private readonly Wolverine.Http.WolverineHttpOptions _wolverineHttpOptions; + + public GET_http_identifier(Wolverine.Http.WolverineHttpOptions wolverineHttpOptions) : base(wolverineHttpOptions) + { + _wolverineHttpOptions = wolverineHttpOptions; + } + + + + public override async System.Threading.Tasks.Task Handle(Microsoft.AspNetCore.Http.HttpContext httpContext) + { + var httpContextEndpoints = new WolverineWebApi.HttpContextEndpoints(); + + // The actual HTTP request handler execution + var result_of_UseTraceIdentifier = httpContextEndpoints.UseTraceIdentifier(httpContext.TraceIdentifier); + + await WriteString(httpContext, result_of_UseTraceIdentifier); + } + + } + + // END: GET_http_identifier + + +} + diff --git a/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/GET_http_principal.cs b/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/GET_http_principal.cs new file mode 100644 index 000000000..fcbbe54fc --- /dev/null +++ b/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/GET_http_principal.cs @@ -0,0 +1,40 @@ +// +#pragma warning disable +using Microsoft.AspNetCore.Routing; +using System; +using System.Linq; +using Wolverine.Http; + +namespace Internal.Generated.WolverineHandlers +{ + // START: GET_http_principal + public class GET_http_principal : Wolverine.Http.HttpHandler + { + private readonly Wolverine.Http.WolverineHttpOptions _wolverineHttpOptions; + + public GET_http_principal(Wolverine.Http.WolverineHttpOptions wolverineHttpOptions) : base(wolverineHttpOptions) + { + _wolverineHttpOptions = wolverineHttpOptions; + } + + + + public override System.Threading.Tasks.Task Handle(Microsoft.AspNetCore.Http.HttpContext httpContext) + { + var httpContextEndpoints = new WolverineWebApi.HttpContextEndpoints(); + + // The actual HTTP request handler execution + httpContextEndpoints.UseClaimsPrincipal(httpContext.User); + + // Wolverine automatically sets the status code to 204 for empty responses + if (!httpContext.Response.HasStarted) httpContext.Response.StatusCode = 204; + return System.Threading.Tasks.Task.CompletedTask; + } + + } + + // END: GET_http_principal + + +} + diff --git a/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/GET_http_request.cs b/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/GET_http_request.cs new file mode 100644 index 000000000..5c5e89a84 --- /dev/null +++ b/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/GET_http_request.cs @@ -0,0 +1,40 @@ +// +#pragma warning disable +using Microsoft.AspNetCore.Routing; +using System; +using System.Linq; +using Wolverine.Http; + +namespace Internal.Generated.WolverineHandlers +{ + // START: GET_http_request + public class GET_http_request : Wolverine.Http.HttpHandler + { + private readonly Wolverine.Http.WolverineHttpOptions _wolverineHttpOptions; + + public GET_http_request(Wolverine.Http.WolverineHttpOptions wolverineHttpOptions) : base(wolverineHttpOptions) + { + _wolverineHttpOptions = wolverineHttpOptions; + } + + + + public override System.Threading.Tasks.Task Handle(Microsoft.AspNetCore.Http.HttpContext httpContext) + { + var httpContextEndpoints = new WolverineWebApi.HttpContextEndpoints(); + + // The actual HTTP request handler execution + httpContextEndpoints.UseHttpRequest(httpContext.Request); + + // Wolverine automatically sets the status code to 204 for empty responses + if (!httpContext.Response.HasStarted) httpContext.Response.StatusCode = 204; + return System.Threading.Tasks.Task.CompletedTask; + } + + } + + // END: GET_http_request + + +} + diff --git a/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/GET_http_response.cs b/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/GET_http_response.cs new file mode 100644 index 000000000..a3ba0647d --- /dev/null +++ b/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/GET_http_response.cs @@ -0,0 +1,40 @@ +// +#pragma warning disable +using Microsoft.AspNetCore.Routing; +using System; +using System.Linq; +using Wolverine.Http; + +namespace Internal.Generated.WolverineHandlers +{ + // START: GET_http_response + public class GET_http_response : Wolverine.Http.HttpHandler + { + private readonly Wolverine.Http.WolverineHttpOptions _wolverineHttpOptions; + + public GET_http_response(Wolverine.Http.WolverineHttpOptions wolverineHttpOptions) : base(wolverineHttpOptions) + { + _wolverineHttpOptions = wolverineHttpOptions; + } + + + + public override System.Threading.Tasks.Task Handle(Microsoft.AspNetCore.Http.HttpContext httpContext) + { + var httpContextEndpoints = new WolverineWebApi.HttpContextEndpoints(); + + // The actual HTTP request handler execution + httpContextEndpoints.UseHttpResponse(httpContext.Response); + + // Wolverine automatically sets the status code to 204 for empty responses + if (!httpContext.Response.HasStarted) httpContext.Response.StatusCode = 204; + return System.Threading.Tasks.Task.CompletedTask; + } + + } + + // END: GET_http_response + + +} + diff --git a/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/GET_invoices_approved.cs b/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/GET_invoices_approved.cs new file mode 100644 index 000000000..65138716b --- /dev/null +++ b/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/GET_invoices_approved.cs @@ -0,0 +1,46 @@ +// +#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_invoices_approved + public class GET_invoices_approved : Wolverine.Http.HttpHandler + { + private readonly Wolverine.Http.WolverineHttpOptions _wolverineHttpOptions; + private readonly Wolverine.Runtime.IWolverineRuntime _wolverineRuntime; + private readonly Wolverine.Marten.Publishing.OutboxedSessionFactory _outboxedSessionFactory; + + public GET_invoices_approved(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 querySession = _outboxedSessionFactory.QuerySession(messageContext); + + // The actual HTTP request handler execution + var approvedInvoicedCompiledQuery = WolverineWebApi.Marten.InvoicesEndpoint.GetApproved(); + + await Marten.AspNetCore.QueryableExtensions.WriteArray>(querySession, approvedInvoicedCompiledQuery, httpContext, "application/json", 200).ConfigureAwait(false); + } + + } + + // END: GET_invoices_approved + + +} + diff --git a/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/GET_invoices_compiled_count.cs b/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/GET_invoices_compiled_count.cs new file mode 100644 index 000000000..a8ceefd35 --- /dev/null +++ b/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/GET_invoices_compiled_count.cs @@ -0,0 +1,47 @@ +// +#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_invoices_compiled_count + public class GET_invoices_compiled_count : Wolverine.Http.HttpHandler + { + private readonly Wolverine.Http.WolverineHttpOptions _wolverineHttpOptions; + private readonly Wolverine.Runtime.IWolverineRuntime _wolverineRuntime; + private readonly Wolverine.Marten.Publishing.OutboxedSessionFactory _outboxedSessionFactory; + + public GET_invoices_compiled_count(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); + + // The actual HTTP request handler execution + var compiledCountQuery = WolverineWebApi.Marten.InvoicesEndpoint.GetCompiledCount(); + + var result_of_QueryAsync = await documentSession.QueryAsync(compiledCountQuery, httpContext.RequestAborted).ConfigureAwait(false); + await Wolverine.Http.HttpHandler.WriteString(httpContext, result_of_QueryAsync.ToString()).ConfigureAwait(false); + } + + } + + // END: GET_invoices_compiled_count + + +} + diff --git a/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/GET_invoices_compiled_id.cs b/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/GET_invoices_compiled_id.cs new file mode 100644 index 000000000..5693010b6 --- /dev/null +++ b/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/GET_invoices_compiled_id.cs @@ -0,0 +1,53 @@ +// +#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_invoices_compiled_id + public class GET_invoices_compiled_id : Wolverine.Http.HttpHandler + { + private readonly Wolverine.Http.WolverineHttpOptions _wolverineHttpOptions; + private readonly Wolverine.Runtime.IWolverineRuntime _wolverineRuntime; + private readonly Wolverine.Marten.Publishing.OutboxedSessionFactory _outboxedSessionFactory; + + public GET_invoices_compiled_id(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 querySession = _outboxedSessionFactory.QuerySession(messageContext); + if (!System.Guid.TryParse((string)httpContext.GetRouteValue("id"), out var id)) + { + httpContext.Response.StatusCode = 404; + return; + } + + + + // The actual HTTP request handler execution + var byIdCompiled = WolverineWebApi.Marten.InvoicesEndpoint.GetCompiled(id); + + await Marten.AspNetCore.QueryableExtensions.WriteOne(querySession, byIdCompiled, httpContext, "application/json", 200).ConfigureAwait(false); + } + + } + + // END: GET_invoices_compiled_id + + +} + diff --git a/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/GET_invoices_id.cs b/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/GET_invoices_id.cs new file mode 100644 index 000000000..197e85b1d --- /dev/null +++ b/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/GET_invoices_id.cs @@ -0,0 +1,70 @@ +// +#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_invoices_id + public class GET_invoices_id : Wolverine.Http.HttpHandler + { + private readonly Wolverine.Http.WolverineHttpOptions _wolverineHttpOptions; + private readonly Wolverine.Runtime.IWolverineRuntime _wolverineRuntime; + private readonly Wolverine.Marten.Publishing.OutboxedSessionFactory _outboxedSessionFactory; + + public GET_invoices_id(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); + if (!System.Guid.TryParse((string)httpContext.GetRouteValue("id"), out var id)) + { + httpContext.Response.StatusCode = 404; + return; + } + + + var invoice = await documentSession.LoadAsync(id, httpContext.RequestAborted).ConfigureAwait(false); + // 404 if this required object is null + if (invoice == null) + { + httpContext.Response.StatusCode = 404; + return; + } + + + // The actual HTTP request handler execution + var invoice_response = WolverineWebApi.Marten.InvoicesEndpoint.Get(invoice); + + + // 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); + + // Writing the response body to JSON because this was the first 'return variable' in the method signature + await WriteJsonAsync(httpContext, invoice_response); + } + + } + + // END: GET_invoices_id + + +} + diff --git a/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/GET_invoices_soft_delete_id.cs b/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/GET_invoices_soft_delete_id.cs new file mode 100644 index 000000000..6fed6ebf8 --- /dev/null +++ b/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/GET_invoices_soft_delete_id.cs @@ -0,0 +1,79 @@ +// +#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_invoices_soft_delete_id + public class GET_invoices_soft_delete_id : Wolverine.Http.HttpHandler + { + private readonly Wolverine.Http.WolverineHttpOptions _wolverineHttpOptions; + private readonly Wolverine.Runtime.IWolverineRuntime _wolverineRuntime; + private readonly Wolverine.Marten.Publishing.OutboxedSessionFactory _outboxedSessionFactory; + + public GET_invoices_soft_delete_id(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) + { + if (!System.Guid.TryParse((string)httpContext.GetRouteValue("id"), out var id)) + { + httpContext.Response.StatusCode = 404; + return; + } + + + var messageContext = new Wolverine.Runtime.MessageContext(_wolverineRuntime); + // Building the Marten session + await using var documentSession = _outboxedSessionFactory.OpenSession(messageContext); + var invoice = await documentSession.LoadAsync(id, httpContext.RequestAborted).ConfigureAwait(false); + // If the document is soft deleted, set the variable to null + var invoiceMetadata = invoice != null + ? await documentSession.MetadataForAsync(invoice).ConfigureAwait(false) + : null; + if (invoiceMetadata?.Deleted == true) + { + invoice = null; + } + + // 404 if this required object is null + if (invoice == null) + { + httpContext.Response.StatusCode = 404; + return; + } + + + // The actual HTTP request handler execution + var invoice_response = WolverineWebApi.Marten.InvoicesEndpoint.GetSoftDeleted(invoice); + + + // 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); + + // Writing the response body to JSON because this was the first 'return variable' in the method signature + await WriteJsonAsync(httpContext, invoice_response); + } + + } + + // END: GET_invoices_soft_delete_id + + +} + diff --git a/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/GET_message_message.cs b/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/GET_message_message.cs new file mode 100644 index 000000000..def329788 --- /dev/null +++ b/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/GET_message_message.cs @@ -0,0 +1,42 @@ +// +#pragma warning disable +using Microsoft.AspNetCore.Routing; +using System; +using System.Linq; +using Wolverine.Http; +using WolverineWebApi; + +namespace Internal.Generated.WolverineHandlers +{ + // START: GET_message_message + public class GET_message_message : Wolverine.Http.HttpHandler + { + private readonly Wolverine.Http.WolverineHttpOptions _wolverineHttpOptions; + private readonly WolverineWebApi.Recorder _recorder; + + public GET_message_message(Wolverine.Http.WolverineHttpOptions wolverineHttpOptions, WolverineWebApi.Recorder recorder) : base(wolverineHttpOptions) + { + _wolverineHttpOptions = wolverineHttpOptions; + _recorder = recorder; + } + + + + public override async System.Threading.Tasks.Task Handle(Microsoft.AspNetCore.Http.HttpContext httpContext) + { + var message = (string)httpContext.GetRouteValue("message"); + var serviceEndpoints = new WolverineWebApi.ServiceEndpoints(); + + // The actual HTTP request handler execution + var result_of_GetMessage = serviceEndpoints.GetMessage(message, _recorder); + + await WriteString(httpContext, result_of_GetMessage); + } + + } + + // END: GET_message_message + + +} + diff --git a/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/GET_middleware_intrinsic.cs b/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/GET_middleware_intrinsic.cs new file mode 100644 index 000000000..901fe1e60 --- /dev/null +++ b/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/GET_middleware_intrinsic.cs @@ -0,0 +1,43 @@ +// +#pragma warning disable +using Microsoft.AspNetCore.Routing; +using System; +using System.Linq; +using Wolverine.Http; +using WolverineWebApi; + +namespace Internal.Generated.WolverineHandlers +{ + // START: GET_middleware_intrinsic + public class GET_middleware_intrinsic : Wolverine.Http.HttpHandler + { + private readonly Wolverine.Http.WolverineHttpOptions _wolverineHttpOptions; + private readonly WolverineWebApi.Recorder _recorder; + + public GET_middleware_intrinsic(Wolverine.Http.WolverineHttpOptions wolverineHttpOptions, WolverineWebApi.Recorder recorder) : base(wolverineHttpOptions) + { + _wolverineHttpOptions = wolverineHttpOptions; + _recorder = recorder; + } + + + + public override async System.Threading.Tasks.Task Handle(Microsoft.AspNetCore.Http.HttpContext httpContext) + { + WolverineWebApi.BeforeAndAfterEndpoint.Before(_recorder); + var beforeAndAfterEndpoint = new WolverineWebApi.BeforeAndAfterEndpoint(); + + // The actual HTTP request handler execution + var result_of_GetRequest = beforeAndAfterEndpoint.GetRequest(_recorder); + + WolverineWebApi.BeforeAndAfterEndpoint.After(_recorder); + await WriteString(httpContext, result_of_GetRequest); + } + + } + + // END: GET_middleware_intrinsic + + +} + diff --git a/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/GET_middleware_simple.cs b/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/GET_middleware_simple.cs new file mode 100644 index 000000000..ad97a7b02 --- /dev/null +++ b/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/GET_middleware_simple.cs @@ -0,0 +1,43 @@ +// +#pragma warning disable +using Microsoft.AspNetCore.Routing; +using System; +using System.Linq; +using Wolverine.Http; +using WolverineWebApi; + +namespace Internal.Generated.WolverineHandlers +{ + // START: GET_middleware_simple + public class GET_middleware_simple : Wolverine.Http.HttpHandler + { + private readonly Wolverine.Http.WolverineHttpOptions _wolverineHttpOptions; + private readonly WolverineWebApi.Recorder _recorder; + + public GET_middleware_simple(Wolverine.Http.WolverineHttpOptions wolverineHttpOptions, WolverineWebApi.Recorder recorder) : base(wolverineHttpOptions) + { + _wolverineHttpOptions = wolverineHttpOptions; + _recorder = recorder; + } + + + + public override async System.Threading.Tasks.Task Handle(Microsoft.AspNetCore.Http.HttpContext httpContext) + { + WolverineWebApi.BeforeAndAfterMiddleware.Before(_recorder); + var middlewareEndpoints = new WolverineWebApi.MiddlewareEndpoints(); + + // The actual HTTP request handler execution + var result_of_GetRequest = middlewareEndpoints.GetRequest(_recorder); + + WolverineWebApi.BeforeAndAfterMiddleware.After(_recorder); + await WriteString(httpContext, result_of_GetRequest); + } + + } + + // END: GET_middleware_simple + + +} + diff --git a/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/GET_name_name.cs b/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/GET_name_name.cs new file mode 100644 index 000000000..94d53159a --- /dev/null +++ b/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/GET_name_name.cs @@ -0,0 +1,39 @@ +// +#pragma warning disable +using Microsoft.AspNetCore.Routing; +using System; +using System.Linq; +using Wolverine.Http; + +namespace Internal.Generated.WolverineHandlers +{ + // START: GET_name_name + public class GET_name_name : Wolverine.Http.HttpHandler + { + private readonly Wolverine.Http.WolverineHttpOptions _wolverineHttpOptions; + + public GET_name_name(Wolverine.Http.WolverineHttpOptions wolverineHttpOptions) : base(wolverineHttpOptions) + { + _wolverineHttpOptions = wolverineHttpOptions; + } + + + + public override async System.Threading.Tasks.Task Handle(Microsoft.AspNetCore.Http.HttpContext httpContext) + { + var name = (string)httpContext.GetRouteValue("name"); + // Just saying hello in the code! Also testing the usage of attributes to customize endpoints + + // The actual HTTP request handler execution + var result_of_SimpleStringRouteArgument = WolverineWebApi.TestEndpoints.SimpleStringRouteArgument(name); + + await WriteString(httpContext, result_of_SimpleStringRouteArgument); + } + + } + + // END: GET_name_name + + +} + diff --git a/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/GET_querystring_collection_enum.cs b/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/GET_querystring_collection_enum.cs new file mode 100644 index 000000000..b158e1da7 --- /dev/null +++ b/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/GET_querystring_collection_enum.cs @@ -0,0 +1,47 @@ +// +#pragma warning disable +using Microsoft.AspNetCore.Routing; +using System; +using System.Linq; +using Wolverine.Http; + +namespace Internal.Generated.WolverineHandlers +{ + // START: GET_querystring_collection_enum + public class GET_querystring_collection_enum : Wolverine.Http.HttpHandler + { + private readonly Wolverine.Http.WolverineHttpOptions _wolverineHttpOptions; + + public GET_querystring_collection_enum(Wolverine.Http.WolverineHttpOptions wolverineHttpOptions) : base(wolverineHttpOptions) + { + _wolverineHttpOptions = wolverineHttpOptions; + } + + + + public override async System.Threading.Tasks.Task Handle(Microsoft.AspNetCore.Http.HttpContext httpContext) + { + var collection = new System.Collections.Generic.List(); + foreach (var collectionValue in httpContext.Request.Query["collection"]) + { + if (WolverineWebApi.Direction.TryParse(collectionValue, out var collectionValueParsed)) + { + collection.Add(collectionValueParsed); + } + + } + + + // The actual HTTP request handler execution + var result_of_UsingEnumCollection = WolverineWebApi.QuerystringCollectionEndpoints.UsingEnumCollection(collection); + + await WriteString(httpContext, result_of_UsingEnumCollection); + } + + } + + // END: GET_querystring_collection_enum + + +} + diff --git a/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/GET_querystring_collection_guid.cs b/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/GET_querystring_collection_guid.cs new file mode 100644 index 000000000..0baadddce --- /dev/null +++ b/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/GET_querystring_collection_guid.cs @@ -0,0 +1,47 @@ +// +#pragma warning disable +using Microsoft.AspNetCore.Routing; +using System; +using System.Linq; +using Wolverine.Http; + +namespace Internal.Generated.WolverineHandlers +{ + // START: GET_querystring_collection_guid + public class GET_querystring_collection_guid : Wolverine.Http.HttpHandler + { + private readonly Wolverine.Http.WolverineHttpOptions _wolverineHttpOptions; + + public GET_querystring_collection_guid(Wolverine.Http.WolverineHttpOptions wolverineHttpOptions) : base(wolverineHttpOptions) + { + _wolverineHttpOptions = wolverineHttpOptions; + } + + + + public override async System.Threading.Tasks.Task Handle(Microsoft.AspNetCore.Http.HttpContext httpContext) + { + var collection = new System.Collections.Generic.List(); + foreach (var collectionValue in httpContext.Request.Query["collection"]) + { + if (System.Guid.TryParse(collectionValue, System.Globalization.CultureInfo.InvariantCulture, out var collectionValueParsed)) + { + collection.Add(collectionValueParsed); + } + + } + + + // The actual HTTP request handler execution + var result_of_UsingGuidCollection = WolverineWebApi.QuerystringCollectionEndpoints.UsingGuidCollection(collection); + + await WriteString(httpContext, result_of_UsingGuidCollection); + } + + } + + // END: GET_querystring_collection_guid + + +} + diff --git a/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/GET_querystring_collection_int.cs b/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/GET_querystring_collection_int.cs new file mode 100644 index 000000000..abbcd70ec --- /dev/null +++ b/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/GET_querystring_collection_int.cs @@ -0,0 +1,47 @@ +// +#pragma warning disable +using Microsoft.AspNetCore.Routing; +using System; +using System.Linq; +using Wolverine.Http; + +namespace Internal.Generated.WolverineHandlers +{ + // START: GET_querystring_collection_int + public class GET_querystring_collection_int : Wolverine.Http.HttpHandler + { + private readonly Wolverine.Http.WolverineHttpOptions _wolverineHttpOptions; + + public GET_querystring_collection_int(Wolverine.Http.WolverineHttpOptions wolverineHttpOptions) : base(wolverineHttpOptions) + { + _wolverineHttpOptions = wolverineHttpOptions; + } + + + + public override async System.Threading.Tasks.Task Handle(Microsoft.AspNetCore.Http.HttpContext httpContext) + { + var collection = new System.Collections.Generic.List(); + foreach (var collectionValue in httpContext.Request.Query["collection"]) + { + if (int.TryParse(collectionValue, System.Globalization.CultureInfo.InvariantCulture, out var collectionValueParsed)) + { + collection.Add(collectionValueParsed); + } + + } + + + // The actual HTTP request handler execution + var result_of_UsingIntCollection = WolverineWebApi.QuerystringCollectionEndpoints.UsingIntCollection(collection); + + await WriteString(httpContext, result_of_UsingIntCollection); + } + + } + + // END: GET_querystring_collection_int + + +} + diff --git a/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/GET_querystring_collection_string.cs b/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/GET_querystring_collection_string.cs new file mode 100644 index 000000000..fa94b12c1 --- /dev/null +++ b/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/GET_querystring_collection_string.cs @@ -0,0 +1,39 @@ +// +#pragma warning disable +using Microsoft.AspNetCore.Routing; +using System; +using System.Linq; +using Wolverine.Http; + +namespace Internal.Generated.WolverineHandlers +{ + // START: GET_querystring_collection_string + public class GET_querystring_collection_string : Wolverine.Http.HttpHandler + { + private readonly Wolverine.Http.WolverineHttpOptions _wolverineHttpOptions; + + public GET_querystring_collection_string(Wolverine.Http.WolverineHttpOptions wolverineHttpOptions) : base(wolverineHttpOptions) + { + _wolverineHttpOptions = wolverineHttpOptions; + } + + + + public override async System.Threading.Tasks.Task Handle(Microsoft.AspNetCore.Http.HttpContext httpContext) + { + var collection = new System.Collections.Generic.List(); + collection.AddRange(httpContext.Request.Query["collection"]); + + // The actual HTTP request handler execution + var result_of_UsingStringCollection = WolverineWebApi.QuerystringCollectionEndpoints.UsingStringCollection(collection); + + await WriteString(httpContext, result_of_UsingStringCollection); + } + + } + + // END: GET_querystring_collection_string + + +} + diff --git a/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/GET_querystring_decimal.cs b/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/GET_querystring_decimal.cs new file mode 100644 index 000000000..b352a57f9 --- /dev/null +++ b/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/GET_querystring_decimal.cs @@ -0,0 +1,43 @@ +// +#pragma warning disable +using Microsoft.AspNetCore.Routing; +using System; +using System.Linq; +using Wolverine.Http; +using WolverineWebApi; + +namespace Internal.Generated.WolverineHandlers +{ + // START: GET_querystring_decimal + public class GET_querystring_decimal : Wolverine.Http.HttpHandler + { + private readonly Wolverine.Http.WolverineHttpOptions _wolverineHttpOptions; + private readonly WolverineWebApi.Recorder _recorder; + + public GET_querystring_decimal(Wolverine.Http.WolverineHttpOptions wolverineHttpOptions, WolverineWebApi.Recorder recorder) : base(wolverineHttpOptions) + { + _wolverineHttpOptions = wolverineHttpOptions; + _recorder = recorder; + } + + + + public override async System.Threading.Tasks.Task Handle(Microsoft.AspNetCore.Http.HttpContext httpContext) + { + System.Decimal amount = default; + System.Decimal.TryParse(httpContext.Request.Query["amount"], System.Globalization.CultureInfo.InvariantCulture, out amount); + // Just saying hello in the code! Also testing the usage of attributes to customize endpoints + + // The actual HTTP request handler execution + var result_of_UseQueryStringParsing = WolverineWebApi.TestEndpoints.UseQueryStringParsing(_recorder, amount); + + await WriteString(httpContext, result_of_UseQueryStringParsing); + } + + } + + // END: GET_querystring_decimal + + +} + diff --git a/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/GET_querystring_enum.cs b/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/GET_querystring_enum.cs new file mode 100644 index 000000000..3f6cd8e62 --- /dev/null +++ b/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/GET_querystring_enum.cs @@ -0,0 +1,39 @@ +// +#pragma warning disable +using Microsoft.AspNetCore.Routing; +using System; +using System.Linq; +using Wolverine.Http; + +namespace Internal.Generated.WolverineHandlers +{ + // START: GET_querystring_enum + public class GET_querystring_enum : Wolverine.Http.HttpHandler + { + private readonly Wolverine.Http.WolverineHttpOptions _wolverineHttpOptions; + + public GET_querystring_enum(Wolverine.Http.WolverineHttpOptions wolverineHttpOptions) : base(wolverineHttpOptions) + { + _wolverineHttpOptions = wolverineHttpOptions; + } + + + + public override async System.Threading.Tasks.Task Handle(Microsoft.AspNetCore.Http.HttpContext httpContext) + { + WolverineWebApi.Direction direction = default; + WolverineWebApi.Direction.TryParse(httpContext.Request.Query["direction"], out direction); + + // The actual HTTP request handler execution + var result_of_UsingEnumQuerystring = WolverineWebApi.QuerystringEndpoints.UsingEnumQuerystring(direction); + + await WriteString(httpContext, result_of_UsingEnumQuerystring); + } + + } + + // END: GET_querystring_enum + + +} + diff --git a/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/GET_querystring_explicit.cs b/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/GET_querystring_explicit.cs new file mode 100644 index 000000000..0c717e5d8 --- /dev/null +++ b/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/GET_querystring_explicit.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_querystring_explicit + public class GET_querystring_explicit : Wolverine.Http.HttpHandler + { + private readonly Wolverine.Http.WolverineHttpOptions _wolverineHttpOptions; + + public GET_querystring_explicit(Wolverine.Http.WolverineHttpOptions wolverineHttpOptions) : base(wolverineHttpOptions) + { + _wolverineHttpOptions = wolverineHttpOptions; + } + + + + public override async System.Threading.Tasks.Task Handle(Microsoft.AspNetCore.Http.HttpContext httpContext) + { + string name = httpContext.Request.Query["name"].FirstOrDefault(); + + // The actual HTTP request handler execution + var result_of_UsingEnumQuerystring = WolverineWebApi.QuerystringEndpoints.UsingEnumQuerystring(name); + + await WriteString(httpContext, result_of_UsingEnumQuerystring); + } + + } + + // END: GET_querystring_explicit + + +} + diff --git a/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/GET_querystring_int.cs b/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/GET_querystring_int.cs new file mode 100644 index 000000000..323321c85 --- /dev/null +++ b/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/GET_querystring_int.cs @@ -0,0 +1,43 @@ +// +#pragma warning disable +using Microsoft.AspNetCore.Routing; +using System; +using System.Linq; +using Wolverine.Http; +using WolverineWebApi; + +namespace Internal.Generated.WolverineHandlers +{ + // START: GET_querystring_int + public class GET_querystring_int : Wolverine.Http.HttpHandler + { + private readonly Wolverine.Http.WolverineHttpOptions _wolverineHttpOptions; + private readonly WolverineWebApi.Recorder _recorder; + + public GET_querystring_int(Wolverine.Http.WolverineHttpOptions wolverineHttpOptions, WolverineWebApi.Recorder recorder) : base(wolverineHttpOptions) + { + _wolverineHttpOptions = wolverineHttpOptions; + _recorder = recorder; + } + + + + public override async System.Threading.Tasks.Task Handle(Microsoft.AspNetCore.Http.HttpContext httpContext) + { + int? age = null; + if (int.TryParse(httpContext.Request.Query["age"], System.Globalization.CultureInfo.InvariantCulture, out var ageParsed)) age = ageParsed; + // Just saying hello in the code! Also testing the usage of attributes to customize endpoints + + // The actual HTTP request handler execution + var result_of_UsingQueryStringParsing = WolverineWebApi.TestEndpoints.UsingQueryStringParsing(_recorder, age); + + await WriteString(httpContext, result_of_UsingQueryStringParsing); + } + + } + + // END: GET_querystring_int + + +} + diff --git a/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/GET_querystring_int_nullable.cs b/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/GET_querystring_int_nullable.cs new file mode 100644 index 000000000..5f57729e4 --- /dev/null +++ b/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/GET_querystring_int_nullable.cs @@ -0,0 +1,40 @@ +// +#pragma warning disable +using Microsoft.AspNetCore.Routing; +using System; +using System.Linq; +using Wolverine.Http; + +namespace Internal.Generated.WolverineHandlers +{ + // START: GET_querystring_int_nullable + public class GET_querystring_int_nullable : Wolverine.Http.HttpHandler + { + private readonly Wolverine.Http.WolverineHttpOptions _wolverineHttpOptions; + + public GET_querystring_int_nullable(Wolverine.Http.WolverineHttpOptions wolverineHttpOptions) : base(wolverineHttpOptions) + { + _wolverineHttpOptions = wolverineHttpOptions; + } + + + + public override async System.Threading.Tasks.Task Handle(Microsoft.AspNetCore.Http.HttpContext httpContext) + { + int? age = null; + if (int.TryParse(httpContext.Request.Query["age"], System.Globalization.CultureInfo.InvariantCulture, out var ageParsed)) age = ageParsed; + // Just saying hello in the code! Also testing the usage of attributes to customize endpoints + + // The actual HTTP request handler execution + var result_of_UsingQueryStringParsingNullable = WolverineWebApi.TestEndpoints.UsingQueryStringParsingNullable(age); + + await WriteString(httpContext, result_of_UsingQueryStringParsingNullable); + } + + } + + // END: GET_querystring_int_nullable + + +} + diff --git a/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/GET_querystring_intarray.cs b/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/GET_querystring_intarray.cs new file mode 100644 index 000000000..b772a68b3 --- /dev/null +++ b/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/GET_querystring_intarray.cs @@ -0,0 +1,48 @@ +// +#pragma warning disable +using Microsoft.AspNetCore.Routing; +using System; +using System.Linq; +using Wolverine.Http; + +namespace Internal.Generated.WolverineHandlers +{ + // START: GET_querystring_intarray + public class GET_querystring_intarray : Wolverine.Http.HttpHandler + { + private readonly Wolverine.Http.WolverineHttpOptions _wolverineHttpOptions; + + public GET_querystring_intarray(Wolverine.Http.WolverineHttpOptions wolverineHttpOptions) : base(wolverineHttpOptions) + { + _wolverineHttpOptions = wolverineHttpOptions; + } + + + + public override async System.Threading.Tasks.Task Handle(Microsoft.AspNetCore.Http.HttpContext httpContext) + { + var values_List = new System.Collections.Generic.List(); + foreach (var valuesValue in httpContext.Request.Query["values"]) + { + if (int.TryParse(valuesValue, System.Globalization.CultureInfo.InvariantCulture, out var valuesValueParsed)) + { + values_List.Add(valuesValueParsed); + } + + } + + var values = values_List.ToArray(); + + // The actual HTTP request handler execution + var result_of_IntArray = WolverineWebApi.QuerystringEndpoints.IntArray(values); + + await WriteString(httpContext, result_of_IntArray); + } + + } + + // END: GET_querystring_intarray + + +} + diff --git a/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/GET_querystring_string.cs b/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/GET_querystring_string.cs new file mode 100644 index 000000000..44e55e0d6 --- /dev/null +++ b/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/GET_querystring_string.cs @@ -0,0 +1,39 @@ +// +#pragma warning disable +using Microsoft.AspNetCore.Routing; +using System; +using System.Linq; +using Wolverine.Http; + +namespace Internal.Generated.WolverineHandlers +{ + // START: GET_querystring_string + public class GET_querystring_string : Wolverine.Http.HttpHandler + { + private readonly Wolverine.Http.WolverineHttpOptions _wolverineHttpOptions; + + public GET_querystring_string(Wolverine.Http.WolverineHttpOptions wolverineHttpOptions) : base(wolverineHttpOptions) + { + _wolverineHttpOptions = wolverineHttpOptions; + } + + + + public override async System.Threading.Tasks.Task Handle(Microsoft.AspNetCore.Http.HttpContext httpContext) + { + string name = httpContext.Request.Query["name"].FirstOrDefault(); + // Just saying hello in the code! Also testing the usage of attributes to customize endpoints + + // The actual HTTP request handler execution + var result_of_UsingQueryString = WolverineWebApi.TestEndpoints.UsingQueryString(name); + + await WriteString(httpContext, result_of_UsingQueryString); + } + + } + + // END: GET_querystring_string + + +} + diff --git a/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/GET_querystring_stringarray.cs b/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/GET_querystring_stringarray.cs new file mode 100644 index 000000000..572216f00 --- /dev/null +++ b/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/GET_querystring_stringarray.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_querystring_stringarray + public class GET_querystring_stringarray : Wolverine.Http.HttpHandler + { + private readonly Wolverine.Http.WolverineHttpOptions _wolverineHttpOptions; + + public GET_querystring_stringarray(Wolverine.Http.WolverineHttpOptions wolverineHttpOptions) : base(wolverineHttpOptions) + { + _wolverineHttpOptions = wolverineHttpOptions; + } + + + + public override async System.Threading.Tasks.Task Handle(Microsoft.AspNetCore.Http.HttpContext httpContext) + { + var values = httpContext.Request.Query["values"].ToArray(); + + // The actual HTTP request handler execution + var result_of_StringArray = WolverineWebApi.QuerystringEndpoints.StringArray(values); + + await WriteString(httpContext, result_of_StringArray); + } + + } + + // END: GET_querystring_stringarray + + +} + diff --git a/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/GET_result.cs b/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/GET_result.cs new file mode 100644 index 000000000..5f34df967 --- /dev/null +++ b/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/GET_result.cs @@ -0,0 +1,37 @@ +// +#pragma warning disable +using Microsoft.AspNetCore.Routing; +using System; +using System.Linq; +using Wolverine.Http; + +namespace Internal.Generated.WolverineHandlers +{ + // START: GET_result + public class GET_result : Wolverine.Http.HttpHandler + { + private readonly Wolverine.Http.WolverineHttpOptions _wolverineHttpOptions; + + public GET_result(Wolverine.Http.WolverineHttpOptions wolverineHttpOptions) : base(wolverineHttpOptions) + { + _wolverineHttpOptions = wolverineHttpOptions; + } + + + + public override System.Threading.Tasks.Task Handle(Microsoft.AspNetCore.Http.HttpContext httpContext) + { + + // The actual HTTP request handler execution + var result = WolverineWebApi.ResultEndpoints.GetResult(); + + return result.ExecuteAsync(httpContext); + } + + } + + // END: GET_result + + +} + diff --git a/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/GET_result_async.cs b/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/GET_result_async.cs new file mode 100644 index 000000000..19eacbc71 --- /dev/null +++ b/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/GET_result_async.cs @@ -0,0 +1,37 @@ +// +#pragma warning disable +using Microsoft.AspNetCore.Routing; +using System; +using System.Linq; +using Wolverine.Http; + +namespace Internal.Generated.WolverineHandlers +{ + // START: GET_result_async + public class GET_result_async : Wolverine.Http.HttpHandler + { + private readonly Wolverine.Http.WolverineHttpOptions _wolverineHttpOptions; + + public GET_result_async(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 = await WolverineWebApi.ResultEndpoints.GetAsyncResult().ConfigureAwait(false); + + await result.ExecuteAsync(httpContext).ConfigureAwait(false); + } + + } + + // END: GET_result_async + + +} + diff --git a/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/GET_results_static.cs b/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/GET_results_static.cs new file mode 100644 index 000000000..2d8d30c43 --- /dev/null +++ b/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/GET_results_static.cs @@ -0,0 +1,39 @@ +// +#pragma warning disable +using Microsoft.AspNetCore.Routing; +using System; +using System.Linq; +using Wolverine.Http; + +namespace Internal.Generated.WolverineHandlers +{ + // START: GET_results_static + public class GET_results_static : Wolverine.Http.HttpHandler + { + private readonly Wolverine.Http.WolverineHttpOptions _wolverineHttpOptions; + + public GET_results_static(Wolverine.Http.WolverineHttpOptions wolverineHttpOptions) : base(wolverineHttpOptions) + { + _wolverineHttpOptions = wolverineHttpOptions; + } + + + + public override async System.Threading.Tasks.Task Handle(Microsoft.AspNetCore.Http.HttpContext httpContext) + { + // Just saying hello in the code! Also testing the usage of attributes to customize endpoints + + // The actual HTTP request handler execution + var arithmeticResults_response = WolverineWebApi.TestEndpoints.FetchStaticResults(); + + // Writing the response body to JSON because this was the first 'return variable' in the method signature + await WriteJsonAsync(httpContext, arithmeticResults_response); + } + + } + + // END: GET_results_static + + +} + diff --git a/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/GET_wildcard_name.cs b/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/GET_wildcard_name.cs new file mode 100644 index 000000000..3938ff58c --- /dev/null +++ b/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/GET_wildcard_name.cs @@ -0,0 +1,39 @@ +// +#pragma warning disable +using Microsoft.AspNetCore.Routing; +using System; +using System.Linq; +using Wolverine.Http; + +namespace Internal.Generated.WolverineHandlers +{ + // START: GET_wildcard_name + public class GET_wildcard_name : Wolverine.Http.HttpHandler + { + private readonly Wolverine.Http.WolverineHttpOptions _wolverineHttpOptions; + + public GET_wildcard_name(Wolverine.Http.WolverineHttpOptions wolverineHttpOptions) : base(wolverineHttpOptions) + { + _wolverineHttpOptions = wolverineHttpOptions; + } + + + + public override async System.Threading.Tasks.Task Handle(Microsoft.AspNetCore.Http.HttpContext httpContext) + { + var name = (string)httpContext.GetRouteValue("name"); + var wildcardEndpoint = new WolverineWebApi.WildcardEndpoint(); + + // The actual HTTP request handler execution + var result_of_Wildcard = wildcardEndpoint.Wildcard(name); + + await WriteString(httpContext, result_of_Wildcard); + } + + } + + // END: GET_wildcard_name + + +} + diff --git a/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/GET_write_to_id.cs b/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/GET_write_to_id.cs new file mode 100644 index 000000000..01df1d3c7 --- /dev/null +++ b/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/GET_write_to_id.cs @@ -0,0 +1,54 @@ +// +#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_write_to_id + public class GET_write_to_id : Wolverine.Http.HttpHandler + { + private readonly Wolverine.Http.WolverineHttpOptions _wolverineHttpOptions; + private readonly Wolverine.Runtime.IWolverineRuntime _wolverineRuntime; + private readonly Wolverine.Marten.Publishing.OutboxedSessionFactory _outboxedSessionFactory; + + public GET_write_to_id(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 querySession = _outboxedSessionFactory.QuerySession(messageContext); + if (!System.Guid.TryParse((string)httpContext.GetRouteValue("id"), out var id)) + { + httpContext.Response.StatusCode = 404; + return; + } + + + + // The actual HTTP request handler execution + await WolverineWebApi.WriteToEndpoints.GetAssetCodeView(id, querySession, httpContext).ConfigureAwait(false); + + // Wolverine automatically sets the status code to 204 for empty responses + if (!httpContext.Response.HasStarted) httpContext.Response.StatusCode = 204; + } + + } + + // END: GET_write_to_id + + +} + diff --git a/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/HttpMessage1Handler862252953.cs b/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/HttpMessage1Handler862252953.cs new file mode 100644 index 000000000..28ebbeaae --- /dev/null +++ b/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/HttpMessage1Handler862252953.cs @@ -0,0 +1,29 @@ +// +#pragma warning disable + +namespace Internal.Generated.WolverineHandlers +{ + // START: HttpMessage1Handler862252953 + public class HttpMessage1Handler862252953 : Wolverine.Runtime.Handlers.MessageHandler + { + + + public override System.Threading.Tasks.Task HandleAsync(Wolverine.Runtime.MessageContext context, System.Threading.CancellationToken cancellation) + { + // The actual message body + var httpMessage1 = (WolverineWebApi.HttpMessage1)context.Envelope.Message; + + + // The actual message execution + WolverineWebApi.MessageHandler.Handle(httpMessage1); + + return System.Threading.Tasks.Task.CompletedTask; + } + + } + + // END: HttpMessage1Handler862252953 + + +} + diff --git a/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/HttpMessage2Handler1265537480.cs b/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/HttpMessage2Handler1265537480.cs new file mode 100644 index 000000000..3bf1a85a0 --- /dev/null +++ b/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/HttpMessage2Handler1265537480.cs @@ -0,0 +1,29 @@ +// +#pragma warning disable + +namespace Internal.Generated.WolverineHandlers +{ + // START: HttpMessage2Handler1265537480 + public class HttpMessage2Handler1265537480 : Wolverine.Runtime.Handlers.MessageHandler + { + + + public override System.Threading.Tasks.Task HandleAsync(Wolverine.Runtime.MessageContext context, System.Threading.CancellationToken cancellation) + { + // The actual message body + var httpMessage2 = (WolverineWebApi.HttpMessage2)context.Envelope.Message; + + + // The actual message execution + WolverineWebApi.MessageHandler.Handle(httpMessage2); + + return System.Threading.Tasks.Task.CompletedTask; + } + + } + + // END: HttpMessage2Handler1265537480 + + +} + diff --git a/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/HttpMessage3Handler300546461.cs b/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/HttpMessage3Handler300546461.cs new file mode 100644 index 000000000..06ecc2c1f --- /dev/null +++ b/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/HttpMessage3Handler300546461.cs @@ -0,0 +1,29 @@ +// +#pragma warning disable + +namespace Internal.Generated.WolverineHandlers +{ + // START: HttpMessage3Handler300546461 + public class HttpMessage3Handler300546461 : Wolverine.Runtime.Handlers.MessageHandler + { + + + public override System.Threading.Tasks.Task HandleAsync(Wolverine.Runtime.MessageContext context, System.Threading.CancellationToken cancellation) + { + // The actual message body + var httpMessage3 = (WolverineWebApi.HttpMessage3)context.Envelope.Message; + + + // The actual message execution + WolverineWebApi.MessageHandler.Handle(httpMessage3); + + return System.Threading.Tasks.Task.CompletedTask; + } + + } + + // END: HttpMessage3Handler300546461 + + +} + diff --git a/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/HttpMessage4Handler102738066.cs b/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/HttpMessage4Handler102738066.cs new file mode 100644 index 000000000..aca0165db --- /dev/null +++ b/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/HttpMessage4Handler102738066.cs @@ -0,0 +1,29 @@ +// +#pragma warning disable + +namespace Internal.Generated.WolverineHandlers +{ + // START: HttpMessage4Handler102738066 + public class HttpMessage4Handler102738066 : Wolverine.Runtime.Handlers.MessageHandler + { + + + public override System.Threading.Tasks.Task HandleAsync(Wolverine.Runtime.MessageContext context, System.Threading.CancellationToken cancellation) + { + // The actual message body + var httpMessage4 = (WolverineWebApi.HttpMessage4)context.Envelope.Message; + + + // The actual message execution + WolverineWebApi.MessageHandler.Handle(httpMessage4); + + return System.Threading.Tasks.Task.CompletedTask; + } + + } + + // END: HttpMessage4Handler102738066 + + +} + diff --git a/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/HttpMessage5Handler1463345875.cs b/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/HttpMessage5Handler1463345875.cs new file mode 100644 index 000000000..6603c853c --- /dev/null +++ b/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/HttpMessage5Handler1463345875.cs @@ -0,0 +1,29 @@ +// +#pragma warning disable + +namespace Internal.Generated.WolverineHandlers +{ + // START: HttpMessage5Handler1463345875 + public class HttpMessage5Handler1463345875 : Wolverine.Runtime.Handlers.MessageHandler + { + + + public override System.Threading.Tasks.Task HandleAsync(Wolverine.Runtime.MessageContext context, System.Threading.CancellationToken cancellation) + { + // The actual message body + var httpMessage5 = (WolverineWebApi.HttpMessage5)context.Envelope.Message; + + + // The actual message execution + WolverineWebApi.MessageHandler.Handle(httpMessage5); + + return System.Threading.Tasks.Task.CompletedTask; + } + + } + + // END: HttpMessage5Handler1463345875 + + +} + diff --git a/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/ItemCreatedHandler179438836.cs b/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/ItemCreatedHandler179438836.cs new file mode 100644 index 000000000..fd749a55d --- /dev/null +++ b/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/ItemCreatedHandler179438836.cs @@ -0,0 +1,30 @@ +// +#pragma warning disable + +namespace Internal.Generated.WolverineHandlers +{ + // START: ItemCreatedHandler179438836 + public class ItemCreatedHandler179438836 : Wolverine.Runtime.Handlers.MessageHandler + { + + + public override System.Threading.Tasks.Task HandleAsync(Wolverine.Runtime.MessageContext context, System.Threading.CancellationToken cancellation) + { + // The actual message body + var itemCreated = (WolverineWebApi.ItemCreated)context.Envelope.Message; + + var itemCreatedHandler = new WolverineWebApi.ItemCreatedHandler(); + + // The actual message execution + itemCreatedHandler.Handle(itemCreated); + + return System.Threading.Tasks.Task.CompletedTask; + } + + } + + // END: ItemCreatedHandler179438836 + + +} + diff --git a/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/MessageThatAlwaysGoesToDeadLetterHandler1388008025.cs b/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/MessageThatAlwaysGoesToDeadLetterHandler1388008025.cs new file mode 100644 index 000000000..ceb80a058 --- /dev/null +++ b/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/MessageThatAlwaysGoesToDeadLetterHandler1388008025.cs @@ -0,0 +1,29 @@ +// +#pragma warning disable + +namespace Internal.Generated.WolverineHandlers +{ + // START: MessageThatAlwaysGoesToDeadLetterHandler1388008025 + public class MessageThatAlwaysGoesToDeadLetterHandler1388008025 : Wolverine.Runtime.Handlers.MessageHandler + { + + + public override System.Threading.Tasks.Task HandleAsync(Wolverine.Runtime.MessageContext context, System.Threading.CancellationToken cancellation) + { + // The actual message body + var messageThatAlwaysGoesToDeadLetter = (WolverineWebApi.MessageThatAlwaysGoesToDeadLetter)context.Envelope.Message; + + + // The actual message execution + WolverineWebApi.MessageHandler.Handle(messageThatAlwaysGoesToDeadLetter); + + return System.Threading.Tasks.Task.CompletedTask; + } + + } + + // END: MessageThatAlwaysGoesToDeadLetterHandler1388008025 + + +} + diff --git a/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/NumberMessageHandler722393759.cs b/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/NumberMessageHandler722393759.cs new file mode 100644 index 000000000..6feb4c0a8 --- /dev/null +++ b/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/NumberMessageHandler722393759.cs @@ -0,0 +1,45 @@ +// +#pragma warning disable +using Microsoft.Extensions.Logging; + +namespace Internal.Generated.WolverineHandlers +{ + // START: NumberMessageHandler722393759 + public class NumberMessageHandler722393759 : Wolverine.Runtime.Handlers.MessageHandler + { + private readonly Microsoft.Extensions.Logging.ILogger _loggerForMessage; + + public NumberMessageHandler722393759(Microsoft.Extensions.Logging.ILogger loggerForMessage) + { + _loggerForMessage = loggerForMessage; + } + + + + public override async System.Threading.Tasks.Task HandleAsync(Wolverine.Runtime.MessageContext context, System.Threading.CancellationToken cancellation) + { + // The actual message body + var numberMessage = (WolverineWebApi.NumberMessage)context.Envelope.Message; + + var problemDetails = WolverineWebApi.NumberMessageHandler.Validate(numberMessage); + // Evaluate whether the processing should stop if there are any problems + if (!(ReferenceEquals(problemDetails, Wolverine.Http.WolverineContinue.NoProblems))) + { + Wolverine.Http.CodeGen.ProblemDetailsContinuationPolicy.WriteProblems(((Microsoft.Extensions.Logging.ILogger)_loggerForMessage), problemDetails); + return; + } + + + + // The actual message execution + WolverineWebApi.NumberMessageHandler.Handle(numberMessage); + + } + + } + + // END: NumberMessageHandler722393759 + + +} + diff --git a/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/POST_api_todo_complete.cs b/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/POST_api_todo_complete.cs new file mode 100644 index 000000000..aff89a2ff --- /dev/null +++ b/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/POST_api_todo_complete.cs @@ -0,0 +1,73 @@ +// +#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_todo_complete + public class POST_api_todo_complete : Wolverine.Http.HttpHandler + { + private readonly Wolverine.Http.WolverineHttpOptions _wolverineHttpOptions; + private readonly Wolverine.Marten.Publishing.OutboxedSessionFactory _outboxedSessionFactory; + private readonly Wolverine.Runtime.IWolverineRuntime _wolverineRuntime; + + public POST_api_todo_complete(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) + { + var messageContext = new Wolverine.Runtime.MessageContext(_wolverineRuntime); + // Building the Marten session + await using var documentSession = _outboxedSessionFactory.OpenSession(messageContext); + // Reading the request body via JSON deserialization + var (command, jsonContinue) = await ReadJsonAsync(httpContext); + if (jsonContinue == Wolverine.HandlerContinuation.Stop) return; + + // Try to load the existing saga document + var todo2 = await documentSession.LoadAsync(command.Id, httpContext.RequestAborted).ConfigureAwait(false); + // 404 if this required object is null + if (todo2 == null) + { + httpContext.Response.StatusCode = 404; + return; + } + + + // The actual HTTP request handler execution + var storageAction = WolverineWebApi.Todos.TodoHandler.Handle(command, todo2); + + if (storageAction != null) + { + Wolverine.Marten.Persistence.Sagas.MartenStorageActionApplier.ApplyAction(documentSession, storageAction); + } + + + // 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.HasStarted) httpContext.Response.StatusCode = 204; + } + + } + + // END: POST_api_todo_complete + + +} + diff --git a/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/POST_api_todo_create.cs b/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/POST_api_todo_create.cs new file mode 100644 index 000000000..daa24c41c --- /dev/null +++ b/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/POST_api_todo_create.cs @@ -0,0 +1,65 @@ +// +#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_todo_create + public class POST_api_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_api_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) + { + var messageContext = new Wolverine.Runtime.MessageContext(_wolverineRuntime); + // Building the Marten session + await using var documentSession = _outboxedSessionFactory.OpenSession(messageContext); + // 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 insert = WolverineWebApi.Todos.TodoHandler.Handle(command); + + if (insert != null) + { + + // Register the document operation with the current session + documentSession.Insert(insert.Entity); + } + + + // 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.HasStarted) httpContext.Response.StatusCode = 204; + } + + } + + // END: POST_api_todo_create + + +} + diff --git a/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/POST_api_todo_create2.cs b/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/POST_api_todo_create2.cs new file mode 100644 index 000000000..107357ac9 --- /dev/null +++ b/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/POST_api_todo_create2.cs @@ -0,0 +1,65 @@ +// +#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_todo_create2 + public class POST_api_todo_create2 : Wolverine.Http.HttpHandler + { + private readonly Wolverine.Http.WolverineHttpOptions _wolverineHttpOptions; + private readonly Wolverine.Marten.Publishing.OutboxedSessionFactory _outboxedSessionFactory; + private readonly Wolverine.Runtime.IWolverineRuntime _wolverineRuntime; + + public POST_api_todo_create2(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) + { + var messageContext = new Wolverine.Runtime.MessageContext(_wolverineRuntime); + // Building the Marten session + await using var documentSession = _outboxedSessionFactory.OpenSession(messageContext); + // 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 store = WolverineWebApi.Todos.TodoHandler.Handle(command); + + if (store != null) + { + + // Register the document operation with the current session + documentSession.Store(store.Entity); + } + + + // 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.HasStarted) httpContext.Response.StatusCode = 204; + } + + } + + // END: POST_api_todo_create2 + + +} + diff --git a/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/POST_api_todo_examinefirst.cs b/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/POST_api_todo_examinefirst.cs new file mode 100644 index 000000000..e40524ccf --- /dev/null +++ b/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/POST_api_todo_examinefirst.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: POST_api_todo_examinefirst + public class POST_api_todo_examinefirst : Wolverine.Http.HttpHandler + { + private readonly Wolverine.Http.WolverineHttpOptions _wolverineHttpOptions; + private readonly Wolverine.Marten.Publishing.OutboxedSessionFactory _outboxedSessionFactory; + private readonly Wolverine.Runtime.IWolverineRuntime _wolverineRuntime; + + public POST_api_todo_examinefirst(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) + { + var messageContext = new Wolverine.Runtime.MessageContext(_wolverineRuntime); + // Building the Marten session + await using var documentSession = _outboxedSessionFactory.OpenSession(messageContext); + // Reading the request body via JSON deserialization + var (command, jsonContinue) = await ReadJsonAsync(httpContext); + if (jsonContinue == Wolverine.HandlerContinuation.Stop) return; + + // Try to load the existing saga document + var todo2 = await documentSession.LoadAsync(command.Todo2Id, httpContext.RequestAborted).ConfigureAwait(false); + // 404 if this required object is null + if (todo2 == null) + { + httpContext.Response.StatusCode = 404; + return; + } + + var result1 = WolverineWebApi.Todos.ExamineFirstHandler.Before(todo2); + // Evaluate whether or not the execution should be stopped based on the IResult value + if (result1 != null && !(result1 is Wolverine.Http.WolverineContinue)) + { + await result1.ExecuteAsync(httpContext).ConfigureAwait(false); + return; + } + + + + // The actual HTTP request handler execution + WolverineWebApi.Todos.ExamineFirstHandler.Handle(command); + + // Wolverine automatically sets the status code to 204 for empty responses + if (!httpContext.Response.HasStarted) httpContext.Response.StatusCode = 204; + } + + } + + // END: POST_api_todo_examinefirst + + +} + diff --git a/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/POST_api_todo_maybecomplete.cs b/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/POST_api_todo_maybecomplete.cs new file mode 100644 index 000000000..63cafad9a --- /dev/null +++ b/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/POST_api_todo_maybecomplete.cs @@ -0,0 +1,66 @@ +// +#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_todo_maybecomplete + public class POST_api_todo_maybecomplete : Wolverine.Http.HttpHandler + { + private readonly Wolverine.Http.WolverineHttpOptions _wolverineHttpOptions; + private readonly Wolverine.Marten.Publishing.OutboxedSessionFactory _outboxedSessionFactory; + private readonly Wolverine.Runtime.IWolverineRuntime _wolverineRuntime; + + public POST_api_todo_maybecomplete(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) + { + var messageContext = new Wolverine.Runtime.MessageContext(_wolverineRuntime); + // Building the Marten session + await using var documentSession = _outboxedSessionFactory.OpenSession(messageContext); + // Reading the request body via JSON deserialization + var (command, jsonContinue) = await ReadJsonAsync(httpContext); + if (jsonContinue == Wolverine.HandlerContinuation.Stop) return; + + // Try to load the existing saga document + var todo2 = await documentSession.LoadAsync(command.Id, httpContext.RequestAborted).ConfigureAwait(false); + + // The actual HTTP request handler execution + var storageAction = WolverineWebApi.Todos.TodoHandler.Handle(command, todo2); + + if (storageAction != null) + { + Wolverine.Marten.Persistence.Sagas.MartenStorageActionApplier.ApplyAction(documentSession, storageAction); + } + + + // 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.HasStarted) httpContext.Response.StatusCode = 204; + } + + } + + // END: POST_api_todo_maybecomplete + + +} + diff --git a/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/POST_api_todo_maybeinsert.cs b/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/POST_api_todo_maybeinsert.cs new file mode 100644 index 000000000..f4b3158c5 --- /dev/null +++ b/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/POST_api_todo_maybeinsert.cs @@ -0,0 +1,63 @@ +// +#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_todo_maybeinsert + public class POST_api_todo_maybeinsert : Wolverine.Http.HttpHandler + { + private readonly Wolverine.Http.WolverineHttpOptions _wolverineHttpOptions; + private readonly Wolverine.Marten.Publishing.OutboxedSessionFactory _outboxedSessionFactory; + private readonly Wolverine.Runtime.IWolverineRuntime _wolverineRuntime; + + public POST_api_todo_maybeinsert(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) + { + var messageContext = new Wolverine.Runtime.MessageContext(_wolverineRuntime); + // Building the Marten session + await using var documentSession = _outboxedSessionFactory.OpenSession(messageContext); + // 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 storageAction = WolverineWebApi.Todos.TodoHandler.Handle(command); + + if (storageAction != null) + { + Wolverine.Marten.Persistence.Sagas.MartenStorageActionApplier.ApplyAction(documentSession, storageAction); + } + + + // 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.HasStarted) httpContext.Response.StatusCode = 204; + } + + } + + // END: POST_api_todo_maybeinsert + + +} + diff --git a/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/POST_api_todo_maybetaskcompletewithbeforeusage.cs b/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/POST_api_todo_maybetaskcompletewithbeforeusage.cs new file mode 100644 index 000000000..03ff20485 --- /dev/null +++ b/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/POST_api_todo_maybetaskcompletewithbeforeusage.cs @@ -0,0 +1,76 @@ +// +#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_todo_maybetaskcompletewithbeforeusage + public class POST_api_todo_maybetaskcompletewithbeforeusage : Wolverine.Http.HttpHandler + { + private readonly Wolverine.Http.WolverineHttpOptions _wolverineHttpOptions; + private readonly Wolverine.Marten.Publishing.OutboxedSessionFactory _outboxedSessionFactory; + private readonly Wolverine.Runtime.IWolverineRuntime _wolverineRuntime; + + public POST_api_todo_maybetaskcompletewithbeforeusage(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) + { + var messageContext = new Wolverine.Runtime.MessageContext(_wolverineRuntime); + // Building the Marten session + await using var documentSession = _outboxedSessionFactory.OpenSession(messageContext); + // Reading the request body via JSON deserialization + var (command, jsonContinue) = await ReadJsonAsync(httpContext); + if (jsonContinue == Wolverine.HandlerContinuation.Stop) return; + + // Try to load the existing saga document + var todo2 = await documentSession.LoadAsync(command.Id, httpContext.RequestAborted).ConfigureAwait(false); + // 404 if this required object is null + if (todo2 == null) + { + httpContext.Response.StatusCode = 404; + return; + } + + WolverineWebApi.Todos.MarkTaskCompleteIfBrokenHandler.Before(todo2); + + // The actual HTTP request handler execution + var update = WolverineWebApi.Todos.MarkTaskCompleteIfBrokenHandler.Handle(command, todo2); + + if (update != null) + { + + // Register the document operation with the current session + documentSession.Update(update.Entity); + } + + + // 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.HasStarted) httpContext.Response.StatusCode = 204; + } + + } + + // END: POST_api_todo_maybetaskcompletewithbeforeusage + + +} + diff --git a/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/POST_api_todo_nullaction.cs b/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/POST_api_todo_nullaction.cs new file mode 100644 index 000000000..f08ab4367 --- /dev/null +++ b/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/POST_api_todo_nullaction.cs @@ -0,0 +1,63 @@ +// +#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_todo_nullaction + public class POST_api_todo_nullaction : Wolverine.Http.HttpHandler + { + private readonly Wolverine.Http.WolverineHttpOptions _wolverineHttpOptions; + private readonly Wolverine.Marten.Publishing.OutboxedSessionFactory _outboxedSessionFactory; + private readonly Wolverine.Runtime.IWolverineRuntime _wolverineRuntime; + + public POST_api_todo_nullaction(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) + { + var messageContext = new Wolverine.Runtime.MessageContext(_wolverineRuntime); + // Building the Marten session + await using var documentSession = _outboxedSessionFactory.OpenSession(messageContext); + // 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 storageAction = WolverineWebApi.Todos.TodoHandler.Handle(command); + + if (storageAction != null) + { + Wolverine.Marten.Persistence.Sagas.MartenStorageActionApplier.ApplyAction(documentSession, storageAction); + } + + + // 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.HasStarted) httpContext.Response.StatusCode = 204; + } + + } + + // END: POST_api_todo_nullaction + + +} + diff --git a/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/POST_api_todo_nullinsert.cs b/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/POST_api_todo_nullinsert.cs new file mode 100644 index 000000000..e1e19a72c --- /dev/null +++ b/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/POST_api_todo_nullinsert.cs @@ -0,0 +1,65 @@ +// +#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_todo_nullinsert + public class POST_api_todo_nullinsert : Wolverine.Http.HttpHandler + { + private readonly Wolverine.Http.WolverineHttpOptions _wolverineHttpOptions; + private readonly Wolverine.Marten.Publishing.OutboxedSessionFactory _outboxedSessionFactory; + private readonly Wolverine.Runtime.IWolverineRuntime _wolverineRuntime; + + public POST_api_todo_nullinsert(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) + { + var messageContext = new Wolverine.Runtime.MessageContext(_wolverineRuntime); + // Building the Marten session + await using var documentSession = _outboxedSessionFactory.OpenSession(messageContext); + // 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 insert = WolverineWebApi.Todos.TodoHandler.Handle(command); + + if (insert != null) + { + + // Register the document operation with the current session + documentSession.Insert(insert.Entity); + } + + + // 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.HasStarted) httpContext.Response.StatusCode = 204; + } + + } + + // END: POST_api_todo_nullinsert + + +} + diff --git a/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/POST_api_todo_update.cs b/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/POST_api_todo_update.cs new file mode 100644 index 000000000..25da838c0 --- /dev/null +++ b/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/POST_api_todo_update.cs @@ -0,0 +1,75 @@ +// +#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_todo_update + public class POST_api_todo_update : Wolverine.Http.HttpHandler + { + private readonly Wolverine.Http.WolverineHttpOptions _wolverineHttpOptions; + private readonly Wolverine.Marten.Publishing.OutboxedSessionFactory _outboxedSessionFactory; + private readonly Wolverine.Runtime.IWolverineRuntime _wolverineRuntime; + + public POST_api_todo_update(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) + { + var messageContext = new Wolverine.Runtime.MessageContext(_wolverineRuntime); + // Building the Marten session + await using var documentSession = _outboxedSessionFactory.OpenSession(messageContext); + // Reading the request body via JSON deserialization + var (command, jsonContinue) = await ReadJsonAsync(httpContext); + if (jsonContinue == Wolverine.HandlerContinuation.Stop) return; + + // Try to load the existing saga document + var todo2 = await documentSession.LoadAsync(command.Id, httpContext.RequestAborted).ConfigureAwait(false); + // 404 if this required object is null + if (todo2 == null) + { + httpContext.Response.StatusCode = 404; + return; + } + + + // The actual HTTP request handler execution + var update = WolverineWebApi.Todos.TodoHandler.Handle(command, todo2); + + if (update != null) + { + + // Register the document operation with the current session + documentSession.Update(update.Entity); + } + + + // 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.HasStarted) httpContext.Response.StatusCode = 204; + } + + } + + // END: POST_api_todo_update + + +} + diff --git a/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/POST_api_todo_update2.cs b/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/POST_api_todo_update2.cs new file mode 100644 index 000000000..285bc959d --- /dev/null +++ b/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/POST_api_todo_update2.cs @@ -0,0 +1,75 @@ +// +#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_todo_update2 + public class POST_api_todo_update2 : Wolverine.Http.HttpHandler + { + private readonly Wolverine.Http.WolverineHttpOptions _wolverineHttpOptions; + private readonly Wolverine.Marten.Publishing.OutboxedSessionFactory _outboxedSessionFactory; + private readonly Wolverine.Runtime.IWolverineRuntime _wolverineRuntime; + + public POST_api_todo_update2(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) + { + var messageContext = new Wolverine.Runtime.MessageContext(_wolverineRuntime); + // Building the Marten session + await using var documentSession = _outboxedSessionFactory.OpenSession(messageContext); + // Reading the request body via JSON deserialization + var (command, jsonContinue) = await ReadJsonAsync(httpContext); + if (jsonContinue == Wolverine.HandlerContinuation.Stop) return; + + // Try to load the existing saga document + var todo2 = await documentSession.LoadAsync(command.Todo2Id, httpContext.RequestAborted).ConfigureAwait(false); + // 404 if this required object is null + if (todo2 == null) + { + httpContext.Response.StatusCode = 404; + return; + } + + + // The actual HTTP request handler execution + var update = WolverineWebApi.Todos.TodoHandler.Handle(command, todo2); + + if (update != null) + { + + // Register the document operation with the current session + documentSession.Update(update.Entity); + } + + + // 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.HasStarted) httpContext.Response.StatusCode = 204; + } + + } + + // END: POST_api_todo_update2 + + +} + diff --git a/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/POST_api_todo_update3.cs b/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/POST_api_todo_update3.cs new file mode 100644 index 000000000..904ca054f --- /dev/null +++ b/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/POST_api_todo_update3.cs @@ -0,0 +1,75 @@ +// +#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_todo_update3 + public class POST_api_todo_update3 : Wolverine.Http.HttpHandler + { + private readonly Wolverine.Http.WolverineHttpOptions _wolverineHttpOptions; + private readonly Wolverine.Marten.Publishing.OutboxedSessionFactory _outboxedSessionFactory; + private readonly Wolverine.Runtime.IWolverineRuntime _wolverineRuntime; + + public POST_api_todo_update3(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) + { + var messageContext = new Wolverine.Runtime.MessageContext(_wolverineRuntime); + // Building the Marten session + await using var documentSession = _outboxedSessionFactory.OpenSession(messageContext); + // Reading the request body via JSON deserialization + var (command, jsonContinue) = await ReadJsonAsync(httpContext); + if (jsonContinue == Wolverine.HandlerContinuation.Stop) return; + + // Try to load the existing saga document + var todo2 = await documentSession.LoadAsync(command.Identity, httpContext.RequestAborted).ConfigureAwait(false); + // 404 if this required object is null + if (todo2 == null) + { + httpContext.Response.StatusCode = 404; + return; + } + + + // The actual HTTP request handler execution + var update = WolverineWebApi.Todos.TodoHandler.Handle(command, todo2); + + if (update != null) + { + + // Register the document operation with the current session + documentSession.Update(update.Entity); + } + + + // 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.HasStarted) httpContext.Response.StatusCode = 204; + } + + } + + // END: POST_api_todo_update3 + + +} + diff --git a/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/POST_authenticated.cs b/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/POST_authenticated.cs new file mode 100644 index 000000000..92e230848 --- /dev/null +++ b/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/POST_authenticated.cs @@ -0,0 +1,51 @@ +// +#pragma warning disable +using Microsoft.AspNetCore.Routing; +using System; +using System.Linq; +using Wolverine.Http; + +namespace Internal.Generated.WolverineHandlers +{ + // START: POST_authenticated + public class POST_authenticated : Wolverine.Http.HttpHandler + { + private readonly Wolverine.Http.WolverineHttpOptions _wolverineHttpOptions; + + public POST_authenticated(Wolverine.Http.WolverineHttpOptions wolverineHttpOptions) : base(wolverineHttpOptions) + { + _wolverineHttpOptions = wolverineHttpOptions; + } + + + + public override async System.Threading.Tasks.Task Handle(Microsoft.AspNetCore.Http.HttpContext httpContext) + { + var fakeAuthenticationMiddleware = new WolverineWebApi.FakeAuthenticationMiddleware(); + // Reading the request body via JSON deserialization + var (request, jsonContinue) = await ReadJsonAsync(httpContext); + if (jsonContinue == Wolverine.HandlerContinuation.Stop) return; + var result1 = WolverineWebApi.FakeAuthenticationMiddleware.Before(request); + // Evaluate whether or not the execution should be stopped based on the IResult value + if (result1 != null && !(result1 is Wolverine.Http.WolverineContinue)) + { + await result1.ExecuteAsync(httpContext).ConfigureAwait(false); + return; + } + + + var authenticatedEndpoint = new WolverineWebApi.AuthenticatedEndpoint(); + + // The actual HTTP request handler execution + var result_of_Get = authenticatedEndpoint.Get(request); + + await WriteString(httpContext, result_of_Get); + } + + } + + // END: POST_authenticated + + +} + diff --git a/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/POST_convert_book.cs b/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/POST_convert_book.cs new file mode 100644 index 000000000..97d418220 --- /dev/null +++ b/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/POST_convert_book.cs @@ -0,0 +1,46 @@ +// +#pragma warning disable +using Microsoft.AspNetCore.Routing; +using System; +using System.Linq; +using Wolverine.Http; +using Wolverine.Runtime; + +namespace Internal.Generated.WolverineHandlers +{ + // START: POST_convert_book + public class POST_convert_book : Wolverine.Http.HttpHandler + { + private readonly Wolverine.Http.WolverineHttpOptions _wolverineHttpOptions; + private readonly Wolverine.Runtime.IWolverineRuntime _wolverineRuntime; + + public POST_convert_book(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) + { + var messageContext = new Wolverine.Runtime.MessageContext(_wolverineRuntime); + Wolverine.Http.Runtime.RequestIdMiddleware.Apply(httpContext, messageContext); + // Reading the request body via JSON deserialization + var (@event, jsonContinue) = await ReadJsonAsync(httpContext); + if (jsonContinue == Wolverine.HandlerContinuation.Stop) return; + + // The actual HTTP request handler execution + await WolverineWebApi.Bugs.ConvertBookEndpoint.Post(@event, messageContext, httpContext.RequestAborted).ConfigureAwait(false); + + // Wolverine automatically sets the status code to 204 for empty responses + if (!httpContext.Response.HasStarted) httpContext.Response.StatusCode = 204; + } + + } + + // END: POST_convert_book + + +} + diff --git a/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/POST_ef_create.cs b/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/POST_ef_create.cs new file mode 100644 index 000000000..ff3ff17de --- /dev/null +++ b/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/POST_ef_create.cs @@ -0,0 +1,60 @@ +// +#pragma warning disable +using Microsoft.AspNetCore.Routing; +using Microsoft.EntityFrameworkCore; +using System; +using System.Linq; +using Wolverine.Http; +using Wolverine.Runtime; + +namespace Internal.Generated.WolverineHandlers +{ + // START: POST_ef_create + public class POST_ef_create : Wolverine.Http.HttpHandler + { + private readonly Wolverine.Http.WolverineHttpOptions _wolverineHttpOptions; + private readonly Wolverine.Runtime.IWolverineRuntime _wolverineRuntime; + private readonly Microsoft.EntityFrameworkCore.DbContextOptions _dbContextOptions; + + public POST_ef_create(Wolverine.Http.WolverineHttpOptions wolverineHttpOptions, Wolverine.Runtime.IWolverineRuntime wolverineRuntime, Microsoft.EntityFrameworkCore.DbContextOptions dbContextOptions) : base(wolverineHttpOptions) + { + _wolverineHttpOptions = wolverineHttpOptions; + _wolverineRuntime = wolverineRuntime; + _dbContextOptions = dbContextOptions; + } + + + + public override async System.Threading.Tasks.Task Handle(Microsoft.AspNetCore.Http.HttpContext httpContext) + { + var messageContext = new Wolverine.Runtime.MessageContext(_wolverineRuntime); + var itemsDbContext = new WolverineWebApi.ItemsDbContext(_dbContextOptions); + + // Enroll the DbContext & IMessagingContext in the outgoing Wolverine outbox transaction + var envelopeTransaction = Wolverine.EntityFrameworkCore.WolverineEntityCoreExtensions.BuildTransaction(itemsDbContext, messageContext); + await messageContext.EnlistInOutboxAsync(envelopeTransaction); + // Reading the request body via JSON deserialization + var (command, jsonContinue) = await ReadJsonAsync(httpContext); + if (jsonContinue == Wolverine.HandlerContinuation.Stop) return; + var efCoreEndpoints = new WolverineWebApi.EfCoreEndpoints(); + + // The actual HTTP request handler execution + efCoreEndpoints.CreateItem(command, itemsDbContext); + + + // Added by EF Core Transaction Middleware + var result_of_SaveChangesAsync = await itemsDbContext.SaveChangesAsync(httpContext.RequestAborted).ConfigureAwait(false); + + // If we have separate context for outbox and application, then we need to manually commit the transaction + if (envelopeTransaction is Wolverine.EntityFrameworkCore.Internals.RawDatabaseEnvelopeTransaction rawTx) { await rawTx.CommitAsync(); } + // Wolverine automatically sets the status code to 204 for empty responses + if (!httpContext.Response.HasStarted) httpContext.Response.StatusCode = 204; + } + + } + + // END: POST_ef_create + + +} + diff --git a/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/POST_ef_publish.cs b/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/POST_ef_publish.cs new file mode 100644 index 000000000..4eddb557d --- /dev/null +++ b/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/POST_ef_publish.cs @@ -0,0 +1,65 @@ +// +#pragma warning disable +using Microsoft.AspNetCore.Routing; +using Microsoft.EntityFrameworkCore; +using System; +using System.Linq; +using Wolverine.Http; +using Wolverine.Runtime; + +namespace Internal.Generated.WolverineHandlers +{ + // START: POST_ef_publish + public class POST_ef_publish : Wolverine.Http.HttpHandler + { + private readonly Wolverine.Http.WolverineHttpOptions _wolverineHttpOptions; + private readonly Wolverine.Runtime.IWolverineRuntime _wolverineRuntime; + private readonly Microsoft.EntityFrameworkCore.DbContextOptions _dbContextOptions; + + public POST_ef_publish(Wolverine.Http.WolverineHttpOptions wolverineHttpOptions, Wolverine.Runtime.IWolverineRuntime wolverineRuntime, Microsoft.EntityFrameworkCore.DbContextOptions dbContextOptions) : base(wolverineHttpOptions) + { + _wolverineHttpOptions = wolverineHttpOptions; + _wolverineRuntime = wolverineRuntime; + _dbContextOptions = dbContextOptions; + } + + + + public override async System.Threading.Tasks.Task Handle(Microsoft.AspNetCore.Http.HttpContext httpContext) + { + var messageContext = new Wolverine.Runtime.MessageContext(_wolverineRuntime); + var itemsDbContext = new WolverineWebApi.ItemsDbContext(_dbContextOptions); + Wolverine.Http.Runtime.RequestIdMiddleware.Apply(httpContext, messageContext); + + // Enroll the DbContext & IMessagingContext in the outgoing Wolverine outbox transaction + var envelopeTransaction = Wolverine.EntityFrameworkCore.WolverineEntityCoreExtensions.BuildTransaction(itemsDbContext, messageContext); + await messageContext.EnlistInOutboxAsync(envelopeTransaction); + // Reading the request body via JSON deserialization + var (command, jsonContinue) = await ReadJsonAsync(httpContext); + if (jsonContinue == Wolverine.HandlerContinuation.Stop) return; + var efCoreEndpoints = new WolverineWebApi.EfCoreEndpoints(); + + // The actual HTTP request handler execution + await efCoreEndpoints.PublishItem(command, itemsDbContext, messageContext).ConfigureAwait(false); + + + // Added by EF Core Transaction Middleware + var result_of_SaveChangesAsync = await itemsDbContext.SaveChangesAsync(httpContext.RequestAborted).ConfigureAwait(false); + + // If we have separate context for outbox and application, then we need to manually commit the transaction + if (envelopeTransaction is Wolverine.EntityFrameworkCore.Internals.RawDatabaseEnvelopeTransaction rawTx) { await rawTx.CommitAsync(); } + + // 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.HasStarted) httpContext.Response.StatusCode = 204; + } + + } + + // END: POST_ef_publish + + +} + diff --git a/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/POST_fromservices.cs b/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/POST_fromservices.cs new file mode 100644 index 000000000..2c8e7e3bb --- /dev/null +++ b/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/POST_fromservices.cs @@ -0,0 +1,41 @@ +// +#pragma warning disable +using Microsoft.AspNetCore.Routing; +using System; +using System.Linq; +using Wolverine.Http; +using WolverineWebApi; + +namespace Internal.Generated.WolverineHandlers +{ + // START: POST_fromservices + public class POST_fromservices : Wolverine.Http.HttpHandler + { + private readonly Wolverine.Http.WolverineHttpOptions _wolverineHttpOptions; + private readonly WolverineWebApi.Recorder _recorder; + + public POST_fromservices(Wolverine.Http.WolverineHttpOptions wolverineHttpOptions, WolverineWebApi.Recorder recorder) : base(wolverineHttpOptions) + { + _wolverineHttpOptions = wolverineHttpOptions; + _recorder = recorder; + } + + + + public override async System.Threading.Tasks.Task Handle(Microsoft.AspNetCore.Http.HttpContext httpContext) + { + var attributeEndpoints = new WolverineWebApi.AttributeEndpoints(); + + // The actual HTTP request handler execution + var result_of_PostFromServices = attributeEndpoints.PostFromServices(_recorder); + + await WriteString(httpContext, result_of_PostFromServices); + } + + } + + // END: POST_fromservices + + +} + diff --git a/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/POST_invoices_invoiceId_pay.cs b/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/POST_invoices_invoiceId_pay.cs new file mode 100644 index 000000000..8f9589e11 --- /dev/null +++ b/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/POST_invoices_invoiceId_pay.cs @@ -0,0 +1,78 @@ +// +#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_invoices_invoiceId_pay + public class POST_invoices_invoiceId_pay : Wolverine.Http.HttpHandler + { + private readonly Wolverine.Http.WolverineHttpOptions _wolverineHttpOptions; + private readonly Wolverine.Runtime.IWolverineRuntime _wolverineRuntime; + private readonly Wolverine.Marten.Publishing.OutboxedSessionFactory _outboxedSessionFactory; + + public POST_invoices_invoiceId_pay(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); + if (!System.Guid.TryParse((string)httpContext.GetRouteValue("invoiceId"), out var invoiceId)) + { + httpContext.Response.StatusCode = 404; + return; + } + + + var invoice = await documentSession.LoadAsync(invoiceId, httpContext.RequestAborted).ConfigureAwait(false); + // 404 if this required object is null + if (invoice == null) + { + httpContext.Response.StatusCode = 404; + return; + } + + + // The actual HTTP request handler execution + var martenOp = WolverineWebApi.Marten.InvoicesEndpoint.Pay(invoice); + + 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.HasStarted) httpContext.Response.StatusCode = 204; + } + + } + + // END: POST_invoices_invoiceId_pay + + +} + diff --git a/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/POST_invoices_number_approve.cs b/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/POST_invoices_number_approve.cs new file mode 100644 index 000000000..8ee0d8c9c --- /dev/null +++ b/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/POST_invoices_number_approve.cs @@ -0,0 +1,78 @@ +// +#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_invoices_number_approve + public class POST_invoices_number_approve : Wolverine.Http.HttpHandler + { + private readonly Wolverine.Http.WolverineHttpOptions _wolverineHttpOptions; + private readonly Wolverine.Runtime.IWolverineRuntime _wolverineRuntime; + private readonly Wolverine.Marten.Publishing.OutboxedSessionFactory _outboxedSessionFactory; + + public POST_invoices_number_approve(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); + if (!System.Guid.TryParse((string)httpContext.GetRouteValue("number"), out var number)) + { + httpContext.Response.StatusCode = 404; + return; + } + + + var invoice = await documentSession.LoadAsync(number, httpContext.RequestAborted).ConfigureAwait(false); + // 404 if this required object is null + if (invoice == null) + { + httpContext.Response.StatusCode = 404; + return; + } + + + // The actual HTTP request handler execution + var martenOp = WolverineWebApi.Marten.InvoicesEndpoint.Approve(invoice); + + 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.HasStarted) httpContext.Response.StatusCode = 204; + } + + } + + // END: POST_invoices_number_approve + + +} + diff --git a/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/POST_issue.cs b/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/POST_issue.cs new file mode 100644 index 000000000..9b2e67dc6 --- /dev/null +++ b/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/POST_issue.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: POST_issue + public class POST_issue : Wolverine.Http.HttpHandler + { + private readonly Wolverine.Http.WolverineHttpOptions _wolverineHttpOptions; + private readonly Wolverine.Runtime.IWolverineRuntime _wolverineRuntime; + private readonly Wolverine.Marten.Publishing.OutboxedSessionFactory _outboxedSessionFactory; + + public POST_issue(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); + // Reading the request body via JSON deserialization + var (command, jsonContinue) = await ReadJsonAsync(httpContext); + if (jsonContinue == Wolverine.HandlerContinuation.Stop) return; + var createEndpoint = new WolverineWebApi.CreateEndpoint(); + + // The actual HTTP request handler execution + (var issueCreated_response, var insertDoc) = createEndpoint.Create(command); + + if (insertDoc != null) + { + + // Placed by Wolverine's ISideEffect policy + insertDoc.Execute(documentSession); + + } + + // This response type customizes the HTTP response + ApplyHttpAware(issueCreated_response, httpContext); + + // 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); + + // Writing the response body to JSON because this was the first 'return variable' in the method signature + await WriteJsonAsync(httpContext, issueCreated_response); + } + + } + + // END: POST_issue + + +} + diff --git a/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/POST_middleware_messages_name.cs b/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/POST_middleware_messages_name.cs new file mode 100644 index 000000000..cc5a6d58e --- /dev/null +++ b/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/POST_middleware_messages_name.cs @@ -0,0 +1,62 @@ +// +#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_middleware_messages_name + public class POST_middleware_messages_name : Wolverine.Http.HttpHandler + { + private readonly Wolverine.Http.WolverineHttpOptions _wolverineHttpOptions; + private readonly Wolverine.Marten.Publishing.OutboxedSessionFactory _outboxedSessionFactory; + private readonly Wolverine.Runtime.IWolverineRuntime _wolverineRuntime; + + public POST_middleware_messages_name(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) + { + var messageContext = new Wolverine.Runtime.MessageContext(_wolverineRuntime); + // Building the Marten session + await using var documentSession = _outboxedSessionFactory.OpenSession(messageContext); + Wolverine.Http.Runtime.RequestIdMiddleware.Apply(httpContext, messageContext); + var name = (string)httpContext.GetRouteValue("name"); + var outgoingMessages101 = WolverineWebApi.CascadingEndpoint.Before(name); + + // Outgoing, cascaded message + await messageContext.EnqueueCascadingAsync(outgoingMessages101).ConfigureAwait(false); + + + // The actual HTTP request handler execution + var result_of_Post = WolverineWebApi.CascadingEndpoint.Post(name, documentSession); + + await WolverineWebApi.CascadingEndpoint.After(messageContext, name).ConfigureAwait(false); + + // Save all pending changes to this Marten session + await documentSession.SaveChangesAsync(httpContext.RequestAborted).ConfigureAwait(false); + + await WriteString(httpContext, result_of_Post); + + // 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: POST_middleware_messages_name + + +} + diff --git a/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/POST_notbody.cs b/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/POST_notbody.cs new file mode 100644 index 000000000..7c7631bc0 --- /dev/null +++ b/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/POST_notbody.cs @@ -0,0 +1,41 @@ +// +#pragma warning disable +using Microsoft.AspNetCore.Routing; +using System; +using System.Linq; +using Wolverine.Http; +using WolverineWebApi; + +namespace Internal.Generated.WolverineHandlers +{ + // START: POST_notbody + public class POST_notbody : Wolverine.Http.HttpHandler + { + private readonly Wolverine.Http.WolverineHttpOptions _wolverineHttpOptions; + private readonly WolverineWebApi.Recorder _recorder; + + public POST_notbody(Wolverine.Http.WolverineHttpOptions wolverineHttpOptions, WolverineWebApi.Recorder recorder) : base(wolverineHttpOptions) + { + _wolverineHttpOptions = wolverineHttpOptions; + _recorder = recorder; + } + + + + public override async System.Threading.Tasks.Task Handle(Microsoft.AspNetCore.Http.HttpContext httpContext) + { + var attributeEndpoints = new WolverineWebApi.AttributeEndpoints(); + + // The actual HTTP request handler execution + var result_of_PostNotBody = attributeEndpoints.PostNotBody(_recorder); + + await WriteString(httpContext, result_of_PostNotBody); + } + + } + + // END: POST_notbody + + +} + diff --git a/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/POST_orders_create.cs b/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/POST_orders_create.cs new file mode 100644 index 000000000..3b762d5bf --- /dev/null +++ b/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/POST_orders_create.cs @@ -0,0 +1,58 @@ +// +#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_orders_create + public class POST_orders_create : Wolverine.Http.HttpHandler + { + private readonly Wolverine.Http.WolverineHttpOptions _wolverineHttpOptions; + private readonly Wolverine.Runtime.IWolverineRuntime _wolverineRuntime; + private readonly Wolverine.Marten.Publishing.OutboxedSessionFactory _outboxedSessionFactory; + + public POST_orders_create(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); + // 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 orderStatus_response = WolverineWebApi.Marten.MarkItemEndpoint.StartOrder(command, 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); + + // Writing the response body to JSON because this was the first 'return variable' in the method signature + await WriteJsonAsync(httpContext, orderStatus_response); + } + + } + + // END: POST_orders_create + + +} + diff --git a/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/POST_orders_create2.cs b/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/POST_orders_create2.cs new file mode 100644 index 000000000..63691fe3a --- /dev/null +++ b/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/POST_orders_create2.cs @@ -0,0 +1,79 @@ +// +#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_orders_create2 + public class POST_orders_create2 : Wolverine.Http.HttpHandler + { + private readonly Wolverine.Http.WolverineHttpOptions _wolverineHttpOptions; + private readonly Wolverine.Runtime.IWolverineRuntime _wolverineRuntime; + private readonly Wolverine.Marten.Publishing.OutboxedSessionFactory _outboxedSessionFactory; + + public POST_orders_create2(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); + // Catches any existing stream id collision exceptions + try + { + // 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 orderStatus_response, var startStream) = WolverineWebApi.Marten.MarkItemEndpoint.StartOrder2(command, documentSession); + + if (startStream != null) + { + + // Placed by Wolverine's ISideEffect policy + startStream.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); + + // Writing the response body to JSON because this was the first 'return variable' in the method signature + await WriteJsonAsync(httpContext, orderStatus_response); + } + + + catch(Marten.Exceptions.ExistingStreamIdCollisionException e) + { + await WolverineWebApi.Marten.StreamCollisionExceptionPolicy.RespondWithProblemDetails(e, httpContext); + return; + } + + + } + + } + + // END: POST_orders_create2 + + +} + diff --git a/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/POST_orders_create3.cs b/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/POST_orders_create3.cs new file mode 100644 index 000000000..e3618f908 --- /dev/null +++ b/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/POST_orders_create3.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_orders_create3 + public class POST_orders_create3 : Wolverine.Http.HttpHandler + { + private readonly Wolverine.Http.WolverineHttpOptions _wolverineHttpOptions; + private readonly Wolverine.Runtime.IWolverineRuntime _wolverineRuntime; + private readonly Wolverine.Marten.Publishing.OutboxedSessionFactory _outboxedSessionFactory; + + public POST_orders_create3(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); + // Catches any existing stream id collision exceptions + try + { + // 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 creationResponse_response, var startStream) = WolverineWebApi.Marten.MarkItemEndpoint.StartOrder3(command); + + if (startStream != null) + { + + // Placed by Wolverine's ISideEffect policy + startStream.Execute(documentSession); + + } + + // This response type customizes the HTTP response + ApplyHttpAware(creationResponse_response, httpContext); + + // 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); + + // Writing the response body to JSON because this was the first 'return variable' in the method signature + await WriteJsonAsync(httpContext, creationResponse_response); + } + + + catch(Marten.Exceptions.ExistingStreamIdCollisionException e) + { + await WolverineWebApi.Marten.StreamCollisionExceptionPolicy.RespondWithProblemDetails(e, httpContext); + return; + } + + + } + + } + + // END: POST_orders_create3 + + +} + diff --git a/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/POST_orders_create4.cs b/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/POST_orders_create4.cs new file mode 100644 index 000000000..832f43c65 --- /dev/null +++ b/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/POST_orders_create4.cs @@ -0,0 +1,79 @@ +// +#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_orders_create4 + public class POST_orders_create4 : Wolverine.Http.HttpHandler + { + private readonly Wolverine.Http.WolverineHttpOptions _wolverineHttpOptions; + private readonly Wolverine.Runtime.IWolverineRuntime _wolverineRuntime; + private readonly Wolverine.Marten.Publishing.OutboxedSessionFactory _outboxedSessionFactory; + + public POST_orders_create4(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); + // Catches any existing stream id collision exceptions + try + { + // 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 orderStatus_response, var startStream) = WolverineWebApi.Marten.MarkItemEndpoint.StartOrder4(command); + + if (startStream != null) + { + + // Placed by Wolverine's ISideEffect policy + startStream.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); + + // Writing the response body to JSON because this was the first 'return variable' in the method signature + await WriteJsonAsync(httpContext, orderStatus_response); + } + + + catch(Marten.Exceptions.ExistingStreamIdCollisionException e) + { + await WolverineWebApi.Marten.StreamCollisionExceptionPolicy.RespondWithProblemDetails(e, httpContext); + return; + } + + + } + + } + + // END: POST_orders_create4 + + +} + diff --git a/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/POST_orders_id_confirm.cs b/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/POST_orders_id_confirm.cs new file mode 100644 index 000000000..28b6b7a42 --- /dev/null +++ b/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/POST_orders_id_confirm.cs @@ -0,0 +1,73 @@ +// +#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_orders_id_confirm + public class POST_orders_id_confirm : Wolverine.Http.HttpHandler + { + private readonly Wolverine.Http.WolverineHttpOptions _wolverineHttpOptions; + private readonly Wolverine.Runtime.IWolverineRuntime _wolverineRuntime; + private readonly Wolverine.Marten.Publishing.OutboxedSessionFactory _outboxedSessionFactory; + + public POST_orders_id_confirm(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); + // Reading the request body via JSON deserialization + var (command, jsonContinue) = await ReadJsonAsync(httpContext); + if (jsonContinue == Wolverine.HandlerContinuation.Stop) return; + await using var documentSession = _outboxedSessionFactory.OpenSession(messageContext); + var eventStore = documentSession.Events; + var aggregateId = command.OrderId; + + // Loading Marten aggregate + var eventStream = await eventStore.FetchForWriting(aggregateId, httpContext.RequestAborted).ConfigureAwait(false); + + if (!System.Guid.TryParse((string)httpContext.GetRouteValue("id"), out var id)) + { + httpContext.Response.StatusCode = 404; + return; + } + + + + // The actual HTTP request handler execution + (var acceptResponse_response, var events) = WolverineWebApi.Marten.MarkItemEndpoint.Confirm(command, eventStream.Aggregate); + + if (events != null) + { + + // Capturing any possible events returned from the command handlers + eventStream.AppendMany(events); + + } + + // This response type customizes the HTTP response + ApplyHttpAware(acceptResponse_response, httpContext); + await documentSession.SaveChangesAsync(httpContext.RequestAborted).ConfigureAwait(false); + // Writing the response body to JSON because this was the first 'return variable' in the method signature + await WriteJsonAsync(httpContext, acceptResponse_response); + } + + } + + // END: POST_orders_id_confirm + + +} + diff --git a/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/POST_orders_id_confirm2.cs b/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/POST_orders_id_confirm2.cs new file mode 100644 index 000000000..90058b5f8 --- /dev/null +++ b/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/POST_orders_id_confirm2.cs @@ -0,0 +1,80 @@ +// +#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_orders_id_confirm2 + public class POST_orders_id_confirm2 : Wolverine.Http.HttpHandler + { + private readonly Wolverine.Http.WolverineHttpOptions _wolverineHttpOptions; + private readonly Wolverine.Marten.Publishing.OutboxedSessionFactory _outboxedSessionFactory; + private readonly Wolverine.Runtime.IWolverineRuntime _wolverineRuntime; + + public POST_orders_id_confirm2(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) + { + var messageContext = new Wolverine.Runtime.MessageContext(_wolverineRuntime); + // Reading the request body via JSON deserialization + var (command, jsonContinue) = await ReadJsonAsync(httpContext); + if (jsonContinue == Wolverine.HandlerContinuation.Stop) return; + await using var documentSession = _outboxedSessionFactory.OpenSession(messageContext); + var eventStore = documentSession.Events; + var aggregateId = command.OrderId; + + // Loading Marten aggregate + var eventStream = await eventStore.FetchForWriting(aggregateId, httpContext.RequestAborted).ConfigureAwait(false); + + if (!System.Guid.TryParse((string)httpContext.GetRouteValue("id"), out var id)) + { + httpContext.Response.StatusCode = 404; + return; + } + + + + // The actual HTTP request handler execution + (var updatedAggregate, var events) = WolverineWebApi.Marten.MarkItemEndpoint.ConfirmDifferent(command, eventStream.Aggregate); + + + // Outgoing, cascaded message + await messageContext.EnqueueCascadingAsync(updatedAggregate).ConfigureAwait(false); + + if (events != null) + { + + // Capturing any possible events returned from the command handlers + eventStream.AppendMany(events); + + } + + await documentSession.SaveChangesAsync(httpContext.RequestAborted).ConfigureAwait(false); + var order_response = await eventStore.FetchLatest(aggregateId, httpContext.RequestAborted); + // Writing the response body to JSON because this was the first 'return variable' in the method signature + await WriteJsonAsync(httpContext, order_response); + + // 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: POST_orders_id_confirm2 + + +} + diff --git a/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/POST_orders_itemready.cs b/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/POST_orders_itemready.cs new file mode 100644 index 000000000..2a38af5eb --- /dev/null +++ b/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/POST_orders_itemready.cs @@ -0,0 +1,68 @@ +// +#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_orders_itemready + public class POST_orders_itemready : Wolverine.Http.HttpHandler + { + private readonly Wolverine.Http.WolverineHttpOptions _wolverineHttpOptions; + private readonly Wolverine.Runtime.IWolverineRuntime _wolverineRuntime; + private readonly Wolverine.Marten.Publishing.OutboxedSessionFactory _outboxedSessionFactory; + + public POST_orders_itemready(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); + // Reading the request body via JSON deserialization + var (command, jsonContinue) = await ReadJsonAsync(httpContext); + if (jsonContinue == Wolverine.HandlerContinuation.Stop) return; + await using var documentSession = _outboxedSessionFactory.OpenSession(messageContext); + var eventStore = documentSession.Events; + var aggregateId = command.OrderId; + + // Loading Marten aggregate + var eventStream = await eventStore.FetchForWriting(aggregateId, command.Version, httpContext.RequestAborted).ConfigureAwait(false); + + System.Guid id = default; + System.Guid.TryParse(httpContext.Request.Query["id"], System.Globalization.CultureInfo.InvariantCulture, out id); + long expectedVersion = default; + long.TryParse(httpContext.Request.Query["expectedVersion"], System.Globalization.CultureInfo.InvariantCulture, out expectedVersion); + + // The actual HTTP request handler execution + (var orderStatus_response, var events) = WolverineWebApi.Marten.MarkItemEndpoint.Post(command, eventStream.Aggregate); + + if (events != null) + { + + // Capturing any possible events returned from the command handlers + eventStream.AppendMany(events); + + } + + await documentSession.SaveChangesAsync(httpContext.RequestAborted).ConfigureAwait(false); + // Writing the response body to JSON because this was the first 'return variable' in the method signature + await WriteJsonAsync(httpContext, orderStatus_response); + } + + } + + // END: POST_orders_itemready + + +} + diff --git a/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/POST_orders_orderId_ship2.cs b/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/POST_orders_orderId_ship2.cs new file mode 100644 index 000000000..7b6dda3b9 --- /dev/null +++ b/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/POST_orders_orderId_ship2.cs @@ -0,0 +1,66 @@ +// +#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_orders_orderId_ship2 + public class POST_orders_orderId_ship2 : Wolverine.Http.HttpHandler + { + private readonly Wolverine.Http.WolverineHttpOptions _wolverineHttpOptions; + private readonly Wolverine.Runtime.IWolverineRuntime _wolverineRuntime; + private readonly Wolverine.Marten.Publishing.OutboxedSessionFactory _outboxedSessionFactory; + + public POST_orders_orderId_ship2(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); + if (!System.Guid.TryParse((string)httpContext.GetRouteValue("orderId"), out var orderId)) + { + httpContext.Response.StatusCode = 404; + return; + } + + + // Reading the request body via JSON deserialization + var (command, jsonContinue) = await ReadJsonAsync(httpContext); + if (jsonContinue == Wolverine.HandlerContinuation.Stop) return; + await using var documentSession = _outboxedSessionFactory.OpenSession(messageContext); + var eventStore = documentSession.Events; + var eventStream = await documentSession.Events.FetchForWriting(orderId, httpContext.RequestAborted); + if (eventStream.Aggregate == null) + { + await Microsoft.AspNetCore.Http.Results.NotFound().ExecuteAsync(httpContext); + return; + } + + + // The actual HTTP request handler execution + var orderShipped = WolverineWebApi.Marten.MarkItemEndpoint.Ship(command, eventStream.Aggregate); + + eventStream.AppendOne(orderShipped); + await documentSession.SaveChangesAsync(httpContext.RequestAborted).ConfigureAwait(false); + // Wolverine automatically sets the status code to 204 for empty responses + if (!httpContext.Response.HasStarted) httpContext.Response.StatusCode = 204; + } + + } + + // END: POST_orders_orderId_ship2 + + +} + diff --git a/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/POST_orders_orderId_ship3.cs b/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/POST_orders_orderId_ship3.cs new file mode 100644 index 000000000..cf1e3033a --- /dev/null +++ b/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/POST_orders_orderId_ship3.cs @@ -0,0 +1,63 @@ +// +#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_orders_orderId_ship3 + public class POST_orders_orderId_ship3 : Wolverine.Http.HttpHandler + { + private readonly Wolverine.Http.WolverineHttpOptions _wolverineHttpOptions; + private readonly Wolverine.Runtime.IWolverineRuntime _wolverineRuntime; + private readonly Wolverine.Marten.Publishing.OutboxedSessionFactory _outboxedSessionFactory; + + public POST_orders_orderId_ship3(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); + if (!System.Guid.TryParse((string)httpContext.GetRouteValue("orderId"), out var orderId)) + { + httpContext.Response.StatusCode = 404; + return; + } + + + await using var documentSession = _outboxedSessionFactory.OpenSession(messageContext); + var eventStore = documentSession.Events; + var eventStream = await documentSession.Events.FetchForWriting(orderId, httpContext.RequestAborted); + if (eventStream.Aggregate == null) + { + await Microsoft.AspNetCore.Http.Results.NotFound().ExecuteAsync(httpContext); + return; + } + + + // The actual HTTP request handler execution + var orderShipped = WolverineWebApi.Marten.MarkItemEndpoint.Ship3(eventStream.Aggregate); + + eventStream.AppendOne(orderShipped); + await documentSession.SaveChangesAsync(httpContext.RequestAborted).ConfigureAwait(false); + // Wolverine automatically sets the status code to 204 for empty responses + if (!httpContext.Response.HasStarted) httpContext.Response.StatusCode = 204; + } + + } + + // END: POST_orders_orderId_ship3 + + +} + diff --git a/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/POST_orders_orderId_ship4.cs b/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/POST_orders_orderId_ship4.cs new file mode 100644 index 000000000..0971fdf10 --- /dev/null +++ b/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/POST_orders_orderId_ship4.cs @@ -0,0 +1,63 @@ +// +#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_orders_orderId_ship4 + public class POST_orders_orderId_ship4 : Wolverine.Http.HttpHandler + { + private readonly Wolverine.Http.WolverineHttpOptions _wolverineHttpOptions; + private readonly Wolverine.Runtime.IWolverineRuntime _wolverineRuntime; + private readonly Wolverine.Marten.Publishing.OutboxedSessionFactory _outboxedSessionFactory; + + public POST_orders_orderId_ship4(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) + { + if (!System.Guid.TryParse((string)httpContext.GetRouteValue("orderId"), out var orderId)) + { + httpContext.Response.StatusCode = 404; + return; + } + + + var messageContext = new Wolverine.Runtime.MessageContext(_wolverineRuntime); + await using var documentSession = _outboxedSessionFactory.OpenSession(messageContext); + var eventStore = documentSession.Events; + var eventStream = await documentSession.Events.FetchForWriting(orderId, httpContext.RequestAborted); + if (eventStream.Aggregate == null) + { + await Microsoft.AspNetCore.Http.Results.NotFound().ExecuteAsync(httpContext); + return; + } + + + // The actual HTTP request handler execution + var orderShipped = WolverineWebApi.Marten.MarkItemEndpoint.Ship4(eventStream.Aggregate); + + eventStream.AppendOne(orderShipped); + await documentSession.SaveChangesAsync(httpContext.RequestAborted).ConfigureAwait(false); + // Wolverine automatically sets the status code to 204 for empty responses + if (!httpContext.Response.HasStarted) httpContext.Response.StatusCode = 204; + } + + } + + // END: POST_orders_orderId_ship4 + + +} + diff --git a/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/POST_orders_ship.cs b/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/POST_orders_ship.cs new file mode 100644 index 000000000..5ec200b6d --- /dev/null +++ b/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/POST_orders_ship.cs @@ -0,0 +1,68 @@ +// +#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_orders_ship + public class POST_orders_ship : Wolverine.Http.HttpHandler + { + private readonly Wolverine.Http.WolverineHttpOptions _wolverineHttpOptions; + private readonly Wolverine.Runtime.IWolverineRuntime _wolverineRuntime; + private readonly Wolverine.Marten.Publishing.OutboxedSessionFactory _outboxedSessionFactory; + + public POST_orders_ship(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); + // Reading the request body via JSON deserialization + var (command, jsonContinue) = await ReadJsonAsync(httpContext); + if (jsonContinue == Wolverine.HandlerContinuation.Stop) return; + await using var documentSession = _outboxedSessionFactory.OpenSession(messageContext); + var eventStore = documentSession.Events; + var aggregateId = command.OrderId; + + // Loading Marten aggregate + var eventStream = await eventStore.FetchForWriting(aggregateId, httpContext.RequestAborted).ConfigureAwait(false); + + var problemDetails1 = WolverineWebApi.Marten.CanShipOrderMiddleWare.Before(command, eventStream.Aggregate); + // Evaluate whether the processing should stop if there are any problems + if (!(ReferenceEquals(problemDetails1, Wolverine.Http.WolverineContinue.NoProblems))) + { + await WriteProblems(problemDetails1, httpContext).ConfigureAwait(false); + return; + } + + + System.Guid id = default; + System.Guid.TryParse(httpContext.Request.Query["id"], System.Globalization.CultureInfo.InvariantCulture, out id); + + // The actual HTTP request handler execution + var orderShipped = WolverineWebApi.Marten.MarkItemEndpoint.Ship(command, eventStream.Aggregate); + + eventStream.AppendOne(orderShipped); + await documentSession.SaveChangesAsync(httpContext.RequestAborted).ConfigureAwait(false); + // Wolverine automatically sets the status code to 204 for empty responses + if (!httpContext.Response.HasStarted) httpContext.Response.StatusCode = 204; + } + + } + + // END: POST_orders_ship + + +} + diff --git a/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/POST_problems.cs b/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/POST_problems.cs new file mode 100644 index 000000000..b00ac6dcd --- /dev/null +++ b/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/POST_problems.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_problems + public class POST_problems : Wolverine.Http.HttpHandler + { + private readonly Wolverine.Http.WolverineHttpOptions _wolverineHttpOptions; + + public POST_problems(Wolverine.Http.WolverineHttpOptions wolverineHttpOptions) : base(wolverineHttpOptions) + { + _wolverineHttpOptions = wolverineHttpOptions; + } + + + + public override async System.Threading.Tasks.Task Handle(Microsoft.AspNetCore.Http.HttpContext httpContext) + { + var problemDetailsUsageEndpoint = new WolverineWebApi.ProblemDetailsUsageEndpoint(); + // Reading the request body via JSON deserialization + var (message, jsonContinue) = await ReadJsonAsync(httpContext); + if (jsonContinue == Wolverine.HandlerContinuation.Stop) return; + var problemDetails1 = problemDetailsUsageEndpoint.Before(message); + // Evaluate whether the processing should stop if there are any problems + if (!(ReferenceEquals(problemDetails1, Wolverine.Http.WolverineContinue.NoProblems))) + { + await WriteProblems(problemDetails1, httpContext).ConfigureAwait(false); + return; + } + + + + // The actual HTTP request handler execution + var result_of_Post = WolverineWebApi.ProblemDetailsUsageEndpoint.Post(message); + + await WriteString(httpContext, result_of_Post); + } + + } + + // END: POST_problems + + +} + diff --git a/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/POST_problems2.cs b/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/POST_problems2.cs new file mode 100644 index 000000000..e6e41de80 --- /dev/null +++ b/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/POST_problems2.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_problems2 + public class POST_problems2 : Wolverine.Http.HttpHandler + { + private readonly Wolverine.Http.WolverineHttpOptions _wolverineHttpOptions; + + public POST_problems2(Wolverine.Http.WolverineHttpOptions wolverineHttpOptions) : base(wolverineHttpOptions) + { + _wolverineHttpOptions = wolverineHttpOptions; + } + + + + public override async System.Threading.Tasks.Task Handle(Microsoft.AspNetCore.Http.HttpContext httpContext) + { + // Reading the request body via JSON deserialization + var (message, jsonContinue) = await ReadJsonAsync(httpContext); + if (jsonContinue == Wolverine.HandlerContinuation.Stop) return; + var problemDetails1 = WolverineWebApi.NumberMessageHandler.Validate(message); + // Evaluate whether the processing should stop if there are any problems + if (!(ReferenceEquals(problemDetails1, Wolverine.Http.WolverineContinue.NoProblems))) + { + await WriteProblems(problemDetails1, httpContext).ConfigureAwait(false); + return; + } + + + + // The actual HTTP request handler execution + WolverineWebApi.NumberMessageHandler.Handle(message); + + // Wolverine automatically sets the status code to 204 for empty responses + if (!httpContext.Response.HasStarted) httpContext.Response.StatusCode = 204; + } + + } + + // END: POST_problems2 + + +} + diff --git a/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/POST_publish_marten_message.cs b/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/POST_publish_marten_message.cs new file mode 100644 index 000000000..acb3fb1d7 --- /dev/null +++ b/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/POST_publish_marten_message.cs @@ -0,0 +1,60 @@ +// +#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_publish_marten_message + public class POST_publish_marten_message : Wolverine.Http.HttpHandler + { + private readonly Wolverine.Http.WolverineHttpOptions _wolverineHttpOptions; + private readonly Wolverine.Runtime.IWolverineRuntime _wolverineRuntime; + private readonly Wolverine.Marten.Publishing.OutboxedSessionFactory _outboxedSessionFactory; + + public POST_publish_marten_message(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); + Wolverine.Http.Runtime.RequestIdMiddleware.Apply(httpContext, messageContext); + // Reading the request body via JSON deserialization + var (data, jsonContinue) = await ReadJsonAsync(httpContext); + if (jsonContinue == Wolverine.HandlerContinuation.Stop) return; + var serviceEndpoints = new WolverineWebApi.ServiceEndpoints(); + + // The actual HTTP request handler execution + await serviceEndpoints.PublishData(data, messageContext, documentSession).ConfigureAwait(false); + + + // 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.HasStarted) httpContext.Response.StatusCode = 204; + } + + } + + // END: POST_publish_marten_message + + +} + diff --git a/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/POST_publish_message1.cs b/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/POST_publish_message1.cs new file mode 100644 index 000000000..28d5b11fe --- /dev/null +++ b/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/POST_publish_message1.cs @@ -0,0 +1,46 @@ +// +#pragma warning disable +using Microsoft.AspNetCore.Routing; +using System; +using System.Linq; +using Wolverine.Http; +using Wolverine.Runtime; + +namespace Internal.Generated.WolverineHandlers +{ + // START: POST_publish_message1 + public class POST_publish_message1 : Wolverine.Http.HttpHandler + { + private readonly Wolverine.Http.WolverineHttpOptions _wolverineHttpOptions; + private readonly Wolverine.Runtime.IWolverineRuntime _wolverineRuntime; + + public POST_publish_message1(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) + { + var messageContext = new Wolverine.Runtime.MessageContext(_wolverineRuntime); + Wolverine.Http.Runtime.RequestIdMiddleware.Apply(httpContext, messageContext); + // Reading the request body via JSON deserialization + var (message, jsonContinue) = await ReadJsonAsync(httpContext); + if (jsonContinue == Wolverine.HandlerContinuation.Stop) return; + var publishingEndpoint = new Wolverine.Http.Runtime.PublishingEndpoint(); + + // The actual HTTP request handler execution + var result_of_PublishAsync = await publishingEndpoint.PublishAsync(message, messageContext, httpContext.Response); + + await WriteString(httpContext, result_of_PublishAsync); + } + + } + + // END: POST_publish_message1 + + +} + diff --git a/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/POST_question.cs b/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/POST_question.cs new file mode 100644 index 000000000..0acd72261 --- /dev/null +++ b/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/POST_question.cs @@ -0,0 +1,42 @@ +// +#pragma warning disable +using Microsoft.AspNetCore.Routing; +using System; +using System.Linq; +using Wolverine.Http; + +namespace Internal.Generated.WolverineHandlers +{ + // START: POST_question + public class POST_question : Wolverine.Http.HttpHandler + { + private readonly Wolverine.Http.WolverineHttpOptions _wolverineHttpOptions; + + public POST_question(Wolverine.Http.WolverineHttpOptions wolverineHttpOptions) : base(wolverineHttpOptions) + { + _wolverineHttpOptions = wolverineHttpOptions; + } + + + + public override async System.Threading.Tasks.Task Handle(Microsoft.AspNetCore.Http.HttpContext httpContext) + { + // Reading the request body via JSON deserialization + var (question, jsonContinue) = await ReadJsonAsync(httpContext); + if (jsonContinue == Wolverine.HandlerContinuation.Stop) return; + // Just saying hello in the code! Also testing the usage of attributes to customize endpoints + + // The actual HTTP request handler execution + var arithmeticResults_response = WolverineWebApi.TestEndpoints.PostJson(question); + + // Writing the response body to JSON because this was the first 'return variable' in the method signature + await WriteJsonAsync(httpContext, arithmeticResults_response); + } + + } + + // END: POST_question + + +} + diff --git a/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/POST_reservation.cs b/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/POST_reservation.cs new file mode 100644 index 000000000..e81862eeb --- /dev/null +++ b/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/POST_reservation.cs @@ -0,0 +1,65 @@ +// +#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_reservation + public class POST_reservation : Wolverine.Http.HttpHandler + { + private readonly Wolverine.Http.WolverineHttpOptions _wolverineHttpOptions; + private readonly Wolverine.Runtime.IWolverineRuntime _wolverineRuntime; + private readonly Wolverine.Marten.Publishing.OutboxedSessionFactory _outboxedSessionFactory; + + public POST_reservation(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); + // Reading the request body via JSON deserialization + var (start, jsonContinue) = await ReadJsonAsync(httpContext); + if (jsonContinue == Wolverine.HandlerContinuation.Stop) return; + + // The actual HTTP request handler execution + (var reservationBooked_response, var reservation, var reservationTimeout) = WolverineWebApi.ReservationEndpoint.Post(start); + + + // Register the document operation with the current session + documentSession.Insert(reservation); + + // Outgoing, cascaded message + await messageContext.EnqueueCascadingAsync(reservationTimeout).ConfigureAwait(false); + + + // Save all pending changes to this Marten session + await documentSession.SaveChangesAsync(httpContext.RequestAborted).ConfigureAwait(false); + + // Writing the response body to JSON because this was the first 'return variable' in the method signature + await WriteJsonAsync(httpContext, reservationBooked_response); + + // 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: POST_reservation + + +} + diff --git a/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/POST_send_always_dead_letter.cs b/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/POST_send_always_dead_letter.cs new file mode 100644 index 000000000..1ec96452f --- /dev/null +++ b/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/POST_send_always_dead_letter.cs @@ -0,0 +1,46 @@ +// +#pragma warning disable +using Microsoft.AspNetCore.Routing; +using System; +using System.Linq; +using Wolverine.Http; +using Wolverine.Runtime; + +namespace Internal.Generated.WolverineHandlers +{ + // START: POST_send_always_dead_letter + public class POST_send_always_dead_letter : Wolverine.Http.HttpHandler + { + private readonly Wolverine.Http.WolverineHttpOptions _wolverineHttpOptions; + private readonly Wolverine.Runtime.IWolverineRuntime _wolverineRuntime; + + public POST_send_always_dead_letter(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) + { + var messageContext = new Wolverine.Runtime.MessageContext(_wolverineRuntime); + Wolverine.Http.Runtime.RequestIdMiddleware.Apply(httpContext, messageContext); + // Reading the request body via JSON deserialization + var (message, jsonContinue) = await ReadJsonAsync(httpContext); + if (jsonContinue == Wolverine.HandlerContinuation.Stop) return; + var sendingEndpoint = new Wolverine.Http.Runtime.SendingEndpoint(); + + // The actual HTTP request handler execution + var result_of_SendAsync = await sendingEndpoint.SendAsync(message, messageContext, httpContext.Response); + + await WriteString(httpContext, result_of_SendAsync); + } + + } + + // END: POST_send_always_dead_letter + + +} + diff --git a/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/POST_send_message5.cs b/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/POST_send_message5.cs new file mode 100644 index 000000000..92f1bc4ad --- /dev/null +++ b/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/POST_send_message5.cs @@ -0,0 +1,46 @@ +// +#pragma warning disable +using Microsoft.AspNetCore.Routing; +using System; +using System.Linq; +using Wolverine.Http; +using Wolverine.Runtime; + +namespace Internal.Generated.WolverineHandlers +{ + // START: POST_send_message5 + public class POST_send_message5 : Wolverine.Http.HttpHandler + { + private readonly Wolverine.Http.WolverineHttpOptions _wolverineHttpOptions; + private readonly Wolverine.Runtime.IWolverineRuntime _wolverineRuntime; + + public POST_send_message5(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) + { + var messageContext = new Wolverine.Runtime.MessageContext(_wolverineRuntime); + Wolverine.Http.Runtime.RequestIdMiddleware.Apply(httpContext, messageContext); + // Reading the request body via JSON deserialization + var (message, jsonContinue) = await ReadJsonAsync(httpContext); + if (jsonContinue == Wolverine.HandlerContinuation.Stop) return; + var sendingEndpoint = new Wolverine.Http.Runtime.SendingEndpoint(); + + // The actual HTTP request handler execution + var result_of_SendAsync = await sendingEndpoint.SendAsync(message, messageContext, httpContext.Response); + + await WriteString(httpContext, result_of_SendAsync); + } + + } + + // END: POST_send_message5 + + +} + diff --git a/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/POST_some_id.cs b/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/POST_some_id.cs new file mode 100644 index 000000000..de0949ea2 --- /dev/null +++ b/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/POST_some_id.cs @@ -0,0 +1,75 @@ +// +#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_some_id + public class POST_some_id : Wolverine.Http.HttpHandler + { + private readonly Wolverine.Http.WolverineHttpOptions _wolverineHttpOptions; + private readonly Wolverine.Runtime.IWolverineRuntime _wolverineRuntime; + private readonly Wolverine.Marten.Publishing.OutboxedSessionFactory _outboxedSessionFactory; + + public POST_some_id(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); + // Reading the request body via JSON deserialization + var (request, jsonContinue) = await ReadJsonAsync(httpContext); + if (jsonContinue == Wolverine.HandlerContinuation.Stop) return; + var id = (string)httpContext.GetRouteValue("id"); + var someDocument = await WolverineWebApi.Bugs.SomeEndpoint.LoadAsync(id, documentSession).ConfigureAwait(false); + // 404 if this required object is null + if (someDocument == null) + { + httpContext.Response.StatusCode = 404; + return; + } + + + // The actual HTTP request handler execution + var storeDoc = WolverineWebApi.Bugs.SomeEndpoint.Handle(request, someDocument); + + if (storeDoc != null) + { + + // Placed by Wolverine's ISideEffect policy + storeDoc.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.HasStarted) httpContext.Response.StatusCode = 204; + } + + } + + // END: POST_some_id + + +} + diff --git a/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/POST_spawn.cs b/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/POST_spawn.cs new file mode 100644 index 000000000..3dc82ff93 --- /dev/null +++ b/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/POST_spawn.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: POST_spawn + public class POST_spawn : Wolverine.Http.HttpHandler + { + private readonly Wolverine.Http.WolverineHttpOptions _wolverineHttpOptions; + private readonly Wolverine.Runtime.IWolverineRuntime _wolverineRuntime; + + public POST_spawn(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) + { + var messageContext = new Wolverine.Runtime.MessageContext(_wolverineRuntime); + // Reading the request body via JSON deserialization + var (input, jsonContinue) = await ReadJsonAsync(httpContext); + if (jsonContinue == Wolverine.HandlerContinuation.Stop) return; + + // The actual HTTP request handler execution + (var stringValue, var outgoingMessages) = WolverineWebApi.MessageSpawnerEndpoint.Post(input); + + + // Outgoing, cascaded message + await messageContext.EnqueueCascadingAsync(outgoingMessages).ConfigureAwait(false); + + await WriteString(httpContext, stringValue); + + // 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: POST_spawn + + +} + diff --git a/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/POST_spawn2.cs b/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/POST_spawn2.cs new file mode 100644 index 000000000..6da998037 --- /dev/null +++ b/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/POST_spawn2.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: POST_spawn2 + public class POST_spawn2 : Wolverine.Http.HttpHandler + { + private readonly Wolverine.Http.WolverineHttpOptions _wolverineHttpOptions; + private readonly Wolverine.Runtime.IWolverineRuntime _wolverineRuntime; + + public POST_spawn2(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) + { + var messageContext = new Wolverine.Runtime.MessageContext(_wolverineRuntime); + + // The actual HTTP request handler execution + (var httpMessage1, var httpMessage2) = WolverineWebApi.MessageSpawnerEndpoint.Post(); + + + // Outgoing, cascaded message + await messageContext.EnqueueCascadingAsync(httpMessage1).ConfigureAwait(false); + + + // Outgoing, cascaded message + await messageContext.EnqueueCascadingAsync(httpMessage2).ConfigureAwait(false); + + // Wolverine automatically sets the status code to 204 for empty responses + if (!httpContext.Response.HasStarted) httpContext.Response.StatusCode = 204; + + // 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: POST_spawn2 + + +} + diff --git a/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/POST_status.cs b/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/POST_status.cs new file mode 100644 index 000000000..b7836dbcc --- /dev/null +++ b/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/POST_status.cs @@ -0,0 +1,43 @@ +// +#pragma warning disable +using Microsoft.AspNetCore.Routing; +using Microsoft.Extensions.Logging; +using System; +using System.Linq; +using Wolverine.Http; + +namespace Internal.Generated.WolverineHandlers +{ + // START: POST_status + public class POST_status : Wolverine.Http.HttpHandler + { + private readonly Wolverine.Http.WolverineHttpOptions _wolverineHttpOptions; + private readonly Microsoft.Extensions.Logging.ILogger _loggerForMessage; + + public POST_status(Wolverine.Http.WolverineHttpOptions wolverineHttpOptions, Microsoft.Extensions.Logging.ILogger loggerForMessage) : base(wolverineHttpOptions) + { + _wolverineHttpOptions = wolverineHttpOptions; + _loggerForMessage = loggerForMessage; + } + + + + public override async System.Threading.Tasks.Task Handle(Microsoft.AspNetCore.Http.HttpContext httpContext) + { + // Reading the request body via JSON deserialization + var (request, jsonContinue) = await ReadJsonAsync(httpContext); + if (jsonContinue == Wolverine.HandlerContinuation.Stop) return; + + // The actual HTTP request handler execution + var result_of_PostStatusCode = WolverineWebApi.StatusCodeEndpoint.PostStatusCode(request, ((Microsoft.Extensions.Logging.ILogger)_loggerForMessage)); + + httpContext.Response.StatusCode = result_of_PostStatusCode; + } + + } + + // END: POST_status + + +} + diff --git a/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/POST_users_sign_up.cs b/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/POST_users_sign_up.cs new file mode 100644 index 000000000..04d4a7814 --- /dev/null +++ b/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/POST_users_sign_up.cs @@ -0,0 +1,40 @@ +// +#pragma warning disable +using Microsoft.AspNetCore.Routing; +using System; +using System.Linq; +using Wolverine.Http; + +namespace Internal.Generated.WolverineHandlers +{ + // START: POST_users_sign_up + public class POST_users_sign_up : Wolverine.Http.HttpHandler + { + private readonly Wolverine.Http.WolverineHttpOptions _wolverineHttpOptions; + + public POST_users_sign_up(Wolverine.Http.WolverineHttpOptions wolverineHttpOptions) : base(wolverineHttpOptions) + { + _wolverineHttpOptions = wolverineHttpOptions; + } + + + + public override async System.Threading.Tasks.Task Handle(Microsoft.AspNetCore.Http.HttpContext httpContext) + { + // Reading the request body via JSON deserialization + var (request, jsonContinue) = await ReadJsonAsync(httpContext); + if (jsonContinue == Wolverine.HandlerContinuation.Stop) return; + + // The actual HTTP request handler execution + var result = WolverineWebApi.SignupEndpoint.SignUp(request); + + await result.ExecuteAsync(httpContext).ConfigureAwait(false); + } + + } + + // END: POST_users_sign_up + + +} + diff --git a/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/POST_validate2_customer.cs b/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/POST_validate2_customer.cs new file mode 100644 index 000000000..ba430f7a8 --- /dev/null +++ b/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/POST_validate2_customer.cs @@ -0,0 +1,58 @@ +// +#pragma warning disable +using FluentValidation; +using Microsoft.AspNetCore.Routing; +using System; +using System.Linq; +using Wolverine.Http; +using Wolverine.Http.FluentValidation; + +namespace Internal.Generated.WolverineHandlers +{ + // START: POST_validate2_customer + public class POST_validate2_customer : Wolverine.Http.HttpHandler + { + private readonly Wolverine.Http.WolverineHttpOptions _wolverineHttpOptions; + private readonly Wolverine.Http.FluentValidation.IProblemDetailSource _problemDetailSource; + private readonly FluentValidation.IValidator _validator; + + public POST_validate2_customer(Wolverine.Http.WolverineHttpOptions wolverineHttpOptions, Wolverine.Http.FluentValidation.IProblemDetailSource problemDetailSource, FluentValidation.IValidator validator) : base(wolverineHttpOptions) + { + _wolverineHttpOptions = wolverineHttpOptions; + _problemDetailSource = problemDetailSource; + _validator = validator; + } + + + + public override async System.Threading.Tasks.Task Handle(Microsoft.AspNetCore.Http.HttpContext httpContext) + { + // Reading the request body via JSON deserialization + var (customer, jsonContinue) = await ReadJsonAsync(httpContext); + if (jsonContinue == Wolverine.HandlerContinuation.Stop) return; + + // Execute FluentValidation validators + var result1 = await Wolverine.Http.FluentValidation.Internals.FluentValidationHttpExecutor.ExecuteOne(_validator, _problemDetailSource, customer).ConfigureAwait(false); + + // Evaluate whether or not the execution should be stopped based on the IResult value + if (result1 != null && !(result1 is Wolverine.Http.WolverineContinue)) + { + await result1.ExecuteAsync(httpContext).ConfigureAwait(false); + return; + } + + + + // The actual HTTP request handler execution + var result_of_Post = Wolverine.Http.Tests.DifferentAssembly.Validation.Validated2Endpoint.Post(customer); + + await WriteString(httpContext, result_of_Post); + } + + } + + // END: POST_validate2_customer + + +} + diff --git a/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/POST_validate_customer.cs b/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/POST_validate_customer.cs new file mode 100644 index 000000000..cebddd606 --- /dev/null +++ b/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/POST_validate_customer.cs @@ -0,0 +1,58 @@ +// +#pragma warning disable +using FluentValidation; +using Microsoft.AspNetCore.Routing; +using System; +using System.Linq; +using Wolverine.Http; +using Wolverine.Http.FluentValidation; + +namespace Internal.Generated.WolverineHandlers +{ + // START: POST_validate_customer + public class POST_validate_customer : Wolverine.Http.HttpHandler + { + private readonly Wolverine.Http.WolverineHttpOptions _wolverineHttpOptions; + private readonly FluentValidation.IValidator _validator; + private readonly Wolverine.Http.FluentValidation.IProblemDetailSource _problemDetailSource; + + public POST_validate_customer(Wolverine.Http.WolverineHttpOptions wolverineHttpOptions, FluentValidation.IValidator validator, Wolverine.Http.FluentValidation.IProblemDetailSource problemDetailSource) : base(wolverineHttpOptions) + { + _wolverineHttpOptions = wolverineHttpOptions; + _validator = validator; + _problemDetailSource = problemDetailSource; + } + + + + public override async System.Threading.Tasks.Task Handle(Microsoft.AspNetCore.Http.HttpContext httpContext) + { + // Reading the request body via JSON deserialization + var (customer, jsonContinue) = await ReadJsonAsync(httpContext); + if (jsonContinue == Wolverine.HandlerContinuation.Stop) return; + + // Execute FluentValidation validators + var result1 = await Wolverine.Http.FluentValidation.Internals.FluentValidationHttpExecutor.ExecuteOne(_validator, _problemDetailSource, customer).ConfigureAwait(false); + + // Evaluate whether or not the execution should be stopped based on the IResult value + if (result1 != null && !(result1 is Wolverine.Http.WolverineContinue)) + { + await result1.ExecuteAsync(httpContext).ConfigureAwait(false); + return; + } + + + + // The actual HTTP request handler execution + var result_of_Post = WolverineWebApi.Validation.ValidatedEndpoint.Post(customer); + + await WriteString(httpContext, result_of_Post); + } + + } + + // END: POST_validate_customer + + +} + diff --git a/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/POST_validate_user.cs b/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/POST_validate_user.cs new file mode 100644 index 000000000..c2b8a7b84 --- /dev/null +++ b/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/POST_validate_user.cs @@ -0,0 +1,55 @@ +// +#pragma warning disable +using Microsoft.AspNetCore.Routing; +using System; +using System.Collections.Generic; +using System.Linq; +using Wolverine.Http; +using Wolverine.Http.FluentValidation; + +namespace Internal.Generated.WolverineHandlers +{ + // START: POST_validate_user + public class POST_validate_user : Wolverine.Http.HttpHandler + { + private readonly Wolverine.Http.WolverineHttpOptions _wolverineHttpOptions; + private readonly System.Collections.Generic.IEnumerable> _validatorIEnumerable; + private readonly Wolverine.Http.FluentValidation.IProblemDetailSource _problemDetailSource; + + public POST_validate_user(Wolverine.Http.WolverineHttpOptions wolverineHttpOptions, System.Collections.Generic.IEnumerable> validatorIEnumerable, Wolverine.Http.FluentValidation.IProblemDetailSource problemDetailSource) : base(wolverineHttpOptions) + { + _wolverineHttpOptions = wolverineHttpOptions; + _validatorIEnumerable = validatorIEnumerable; + _problemDetailSource = problemDetailSource; + } + + + + public override async System.Threading.Tasks.Task Handle(Microsoft.AspNetCore.Http.HttpContext httpContext) + { + // Reading the request body via JSON deserialization + var (user, jsonContinue) = await ReadJsonAsync(httpContext); + if (jsonContinue == Wolverine.HandlerContinuation.Stop) return; + var result1 = await Wolverine.Http.FluentValidation.Internals.FluentValidationHttpExecutor.ExecuteMany(_validatorIEnumerable, _problemDetailSource, user).ConfigureAwait(false); + // Evaluate whether or not the execution should be stopped based on the IResult value + if (result1 != null && !(result1 is Wolverine.Http.WolverineContinue)) + { + await result1.ExecuteAsync(httpContext).ConfigureAwait(false); + return; + } + + + + // The actual HTTP request handler execution + var result_of_Post = WolverineWebApi.Validation.ValidatedEndpoint.Post(user); + + await WriteString(httpContext, result_of_Post); + } + + } + + // END: POST_validate_user + + +} + diff --git a/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/PUT_todos2_id.cs b/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/PUT_todos2_id.cs new file mode 100644 index 000000000..5ea9d2138 --- /dev/null +++ b/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/PUT_todos2_id.cs @@ -0,0 +1,74 @@ +// +#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: PUT_todos2_id + public class PUT_todos2_id : Wolverine.Http.HttpHandler + { + private readonly Wolverine.Http.WolverineHttpOptions _wolverineHttpOptions; + private readonly Wolverine.Runtime.IWolverineRuntime _wolverineRuntime; + private readonly Wolverine.Marten.Publishing.OutboxedSessionFactory _outboxedSessionFactory; + + public PUT_todos2_id(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); + if (!int.TryParse((string)httpContext.GetRouteValue("id"), out var id)) + { + httpContext.Response.StatusCode = 404; + return; + } + + + // Reading the request body via JSON deserialization + var (request, jsonContinue) = await ReadJsonAsync(httpContext); + if (jsonContinue == Wolverine.HandlerContinuation.Stop) return; + (var todo, var result1) = await WolverineWebApi.Samples.Update2Endpoint.LoadAsync(id, request, documentSession).ConfigureAwait(false); + // Evaluate whether or not the execution should be stopped based on the IResult value + if (result1 != null && !(result1 is Wolverine.Http.WolverineContinue)) + { + await result1.ExecuteAsync(httpContext).ConfigureAwait(false); + return; + } + + + + // The actual HTTP request handler execution + var todo_response = WolverineWebApi.Samples.Update2Endpoint.Put(id, request, todo, 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); + + // Writing the response body to JSON because this was the first 'return variable' in the method signature + await WriteJsonAsync(httpContext, todo_response); + } + + } + + // END: PUT_todos2_id + + +} + diff --git a/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/PUT_todos_id.cs b/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/PUT_todos_id.cs new file mode 100644 index 000000000..8d21297df --- /dev/null +++ b/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/PUT_todos_id.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: PUT_todos_id + public class PUT_todos_id : Wolverine.Http.HttpHandler + { + private readonly Wolverine.Http.WolverineHttpOptions _wolverineHttpOptions; + private readonly Wolverine.Runtime.IWolverineRuntime _wolverineRuntime; + private readonly Wolverine.Marten.Publishing.OutboxedSessionFactory _outboxedSessionFactory; + + public PUT_todos_id(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); + if (!int.TryParse((string)httpContext.GetRouteValue("id"), out var id)) + { + httpContext.Response.StatusCode = 404; + return; + } + + + // Reading the request body via JSON deserialization + var (request, jsonContinue) = await ReadJsonAsync(httpContext); + if (jsonContinue == Wolverine.HandlerContinuation.Stop) return; + var todo = await WolverineWebApi.Samples.UpdateEndpoint.LoadAsync(id, documentSession).ConfigureAwait(false); + // 404 if this required object is null + if (todo == null) + { + httpContext.Response.StatusCode = 404; + return; + } + + + // The actual HTTP request handler execution + var storeDoc = WolverineWebApi.Samples.UpdateEndpoint.Put(id, request, todo); + + if (storeDoc != null) + { + + // Placed by Wolverine's ISideEffect policy + storeDoc.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.HasStarted) httpContext.Response.StatusCode = 204; + } + + } + + // END: PUT_todos_id + + +} + diff --git a/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/TelegramUpdatedHandler96651444.cs b/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/TelegramUpdatedHandler96651444.cs new file mode 100644 index 000000000..155923aa9 --- /dev/null +++ b/src/Http/WolverineWebApi/Internal/Generated/WolverineHandlers/TelegramUpdatedHandler96651444.cs @@ -0,0 +1,29 @@ +// +#pragma warning disable + +namespace Internal.Generated.WolverineHandlers +{ + // START: TelegramUpdatedHandler96651444 + public class TelegramUpdatedHandler96651444 : Wolverine.Runtime.Handlers.MessageHandler + { + + + public override System.Threading.Tasks.Task HandleAsync(Wolverine.Runtime.MessageContext context, System.Threading.CancellationToken cancellation) + { + // The actual message body + var telegramUpdated = (WolverineWebApi.Bugs.TelegramUpdated)context.Envelope.Message; + + + // The actual message execution + WolverineWebApi.Bugs.TelegramUpdatedHandler.Handle(telegramUpdated); + + return System.Threading.Tasks.Task.CompletedTask; + } + + } + + // END: TelegramUpdatedHandler96651444 + + +} + diff --git a/src/Http/WolverineWebApi/Todos/Todo2.cs b/src/Http/WolverineWebApi/Todos/Todo2.cs new file mode 100644 index 000000000..4efbfd7fb --- /dev/null +++ b/src/Http/WolverineWebApi/Todos/Todo2.cs @@ -0,0 +1,201 @@ +using Marten.Schema; +using Shouldly; +using Wolverine; +using Wolverine.Http; +using Wolverine.Persistence; +using WolverineWebApi.Samples; + +namespace WolverineWebApi.Todos; + +[DocumentAlias("test_todo")] +public class Todo2 +{ + public string Id { get; set; } + public string? Name { get; set; } + public bool IsComplete { get; set; } +} + +public record CreateTodoRequest(string Id, string Name); +public record CreateTodo2(string Id, string Name); + +public record DeleteTodo(string Id); + +#region sample_rename_todo + +public record RenameTodo(string Id, string Name); + +#endregion +public record RenameTodo2(string Todo2Id, string Name); +public record RenameTodo3(string Identity, string Name); + +public record AlterTodo(string Id, string Name, StorageAction Action); + +public record MaybeInsertTodo(string Id, string Name, bool ShouldInsert); + +public record ReturnNullInsert; +public record ReturnNullStorageAction; + + +public static class TodoHandler +{ + [WolverinePost("/api/todo/create")] + public static Insert Handle(CreateTodoRequest command) => Storage.Insert(new Todo2 + { + Id = command.Id, + Name = command.Name + }); + + [WolverinePost("/api/todo/create2")] + public static Store Handle(CreateTodo2 command) => Storage.Store(new Todo2 + { + Id = command.Id, + Name = command.Name + }); + + #region sample_using_entity_attribute + + // Use "Id" as the default member + [WolverinePost("/api/todo/update")] + public static Update Handle( + // The first argument is always the incoming message + RenameTodo command, + + // By using this attribute, we're telling Wolverine + // to load the Todo entity from the configured + // persistence of the app using a member on the + // incoming message type + [Entity] Todo2 todo) + { + // Do your actual business logic + todo.Name = command.Name; + + // Tell Wolverine that you want this entity + // updated in persistence + return Storage.Update(todo); + } + + #endregion + + // Use "TodoId" as the default member + [WolverinePost("/api/todo/update2")] + public static Update Handle(RenameTodo2 command, [Entity] Todo2 todo) + { + todo.Name = command.Name; + return Storage.Update(todo); + } + + // Use the explicit member + [WolverinePost("/api/todo/update3")] + public static Update Handle(RenameTodo3 command, [Entity("Identity")] Todo2 todo) + { + todo.Name = command.Name; + return Storage.Update(todo); + } + + [WolverineDelete("/api/todo/delete")] + public static Delete Handle(DeleteTodo command, [Entity("Identity")] Todo2 todo) + { + return Storage.Delete(todo); + } + + [WolverinePost("/api/todo/alter")] + public static IStorageAction Handle(AlterTodo command, [Entity("Identity")] Todo2 todo) + { + switch (command.Action) + { + case StorageAction.Delete: + return Storage.Delete(todo); + case StorageAction.Update: + todo.Name = command.Name; + return Storage.Update(todo); + case StorageAction.Store: + todo.Name = command.Name; + return Storage.Store(todo); + default: + return Storage.Nothing(); + } + } + + [WolverinePost("/api/todo/maybeinsert")] + public static IStorageAction Handle(MaybeInsertTodo command) + { + if (command.ShouldInsert) + { + return Storage.Insert(new Todo2 { Id = command.Id, Name = command.Name }); + } + + return Storage.Nothing(); + } + + [WolverinePost("/api/todo/nullinsert")] + public static Insert? Handle(ReturnNullInsert command) => null; + + [WolverinePost("/api/todo/nullaction")] + public static IStorageAction? Handle(ReturnNullStorageAction command) => null; + + [WolverinePost("/api/todo/complete")] + public static IStorageAction Handle(CompleteTodo command, [Entity] Todo2 todo) + { + if (todo == null) throw new ArgumentNullException(nameof(todo)); + todo.IsComplete = true; + return Storage.Update(todo); + } + + #region sample_using_not_required_entity_attribute + + [WolverinePost("/api/todo/maybecomplete")] + public static IStorageAction Handle(MaybeCompleteTodo command, [Entity(Required = false)] Todo2? todo) + { + if (todo == null) return Storage.Nothing(); + todo.IsComplete = true; + return Storage.Update(todo); + } + + #endregion + + #region sample_specifying_the_exact_route_argument + + // Okay, I still used "id", but it *could* be something different here! + [WolverineGet("/api/todo/{id}")] + public static Todo2 Get([Entity("id")] Todo2 todo) => todo; + + #endregion +} + +public record CompleteTodo(string Id); +public record MaybeCompleteTodo(string Id); + +public record MarkTaskCompleteWithBeforeUsage(string Id); + +public static class MarkTaskCompleteIfBrokenHandler +{ + // Just proving out that you can get at the entity + // in a Before method + public static void Before(Todo2 todo) + { + todo.ShouldNotBeNull(); + } + + [WolverinePost("/api/todo/maybetaskcompletewithbeforeusage")] + public static Update Handle(MarkTaskCompleteWithBeforeUsage command, [Entity] Todo2 todo) + { + todo.IsComplete = true; + return Storage.Update(todo); + } +} + +public record ExamineFirst(string Todo2Id); + +public static class ExamineFirstHandler +{ + public static bool DidContinue { get; set; } + + public static IResult Before([Entity] Todo2 todo) + { + return todo != null ? WolverineContinue.Result() : Results.Empty; + } + + [WolverinePost("/api/todo/examinefirst")] + public static void Handle(ExamineFirst command) => DidContinue = true; +} + diff --git a/src/Persistence/EfCoreTests/using_storage_return_types_and_entity_attributes.cs b/src/Persistence/EfCoreTests/using_storage_return_types_and_entity_attributes.cs new file mode 100644 index 000000000..1477cfb44 --- /dev/null +++ b/src/Persistence/EfCoreTests/using_storage_return_types_and_entity_attributes.cs @@ -0,0 +1,73 @@ +using IntegrationTests; +using Microsoft.Data.SqlClient; +using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.DependencyInjection; +using Weasel.Core; +using Weasel.SqlServer; +using Weasel.SqlServer.Tables; +using Wolverine; +using Wolverine.ComplianceTests; +using Wolverine.EntityFrameworkCore; +using Wolverine.SqlServer; + +namespace EfCoreTests; + +public class using_storage_return_types_and_entity_attributes : StorageActionCompliance +{ + protected override void configureWolverine(WolverineOptions opts) + { + opts.Services.AddDbContextWithWolverineIntegration(x => + { + x.UseSqlServer(Servers.SqlServerConnectionString); + }, "wolverine"); + + opts.PersistMessagesWithSqlServer(Servers.SqlServerConnectionString); + } + + protected override async Task initialize() + { + var table = new Table(new DbObjectName("todo_app", "todos")); + table.AddColumn("id").AsPrimaryKey(); + table.AddColumn("name"); + table.AddColumn("is_complete"); + + using var conn = new SqlConnection(Servers.SqlServerConnectionString); + await conn.OpenAsync(); + await table.MigrateAsync(conn); + } + + public override async Task Load(string id) + { + using var scope = Host.Services.CreateScope(); + var context = scope.ServiceProvider.GetRequiredService(); + return await context.Todos.FindAsync(id); + } + + public override async Task Persist(Todo todo) + { + using var scope = Host.Services.CreateScope(); + var context = scope.ServiceProvider.GetRequiredService(); + context.Todos.Add(todo); + await context.SaveChangesAsync(); + } +} + +public class TodoDbContext : DbContext +{ + public TodoDbContext(DbContextOptions options) : base(options) + { + } + + public DbSet Todos { get; set; } + + protected override void OnModelCreating(ModelBuilder modelBuilder) + { + modelBuilder.Entity(map => + { + map.ToTable("todos", "todo_app"); + map.HasKey(x => x.Id); + map.Property(x => x.Name); + map.Property(x => x.IsComplete).HasColumnName("is_complete"); + }); + } +} \ No newline at end of file diff --git a/src/Persistence/MartenTests/Internal/Generated/WolverineHandlers/Event3Handler1609469393.cs b/src/Persistence/MartenTests/Internal/Generated/WolverineHandlers/Event3Handler1609469393.cs new file mode 100644 index 000000000..9dd8ef29b --- /dev/null +++ b/src/Persistence/MartenTests/Internal/Generated/WolverineHandlers/Event3Handler1609469393.cs @@ -0,0 +1,48 @@ +// +#pragma warning disable +using Wolverine.Marten.Publishing; + +namespace Internal.Generated.WolverineHandlers +{ + // START: Event3Handler1609469393 + public class Event3Handler1609469393 : Wolverine.Runtime.Handlers.MessageHandler + { + private readonly Wolverine.Marten.Publishing.OutboxedSessionFactory _outboxedSessionFactory; + + public Event3Handler1609469393(Wolverine.Marten.Publishing.OutboxedSessionFactory outboxedSessionFactory) + { + _outboxedSessionFactory = outboxedSessionFactory; + } + + + + public override async System.Threading.Tasks.Task HandleAsync(Wolverine.Runtime.MessageContext context, System.Threading.CancellationToken cancellation) + { + // The actual message body + var event3 = (MartenTests.Event3)context.Envelope.Message; + + await using var documentSession = _outboxedSessionFactory.OpenSession(context); + var eventStore = documentSession.Events; + var aggregateId = event3.AggregateId; + + // Loading Marten aggregate + var eventStream = await eventStore.FetchForWriting(aggregateId, cancellation).ConfigureAwait(false); + + + // The actual message execution + var outgoing1 = MartenTests.FooHandler.Handle(event3, eventStream.Aggregate); + + + // Outgoing, cascaded message + await context.EnqueueCascadingAsync(outgoing1).ConfigureAwait(false); + + await documentSession.SaveChangesAsync(cancellation).ConfigureAwait(false); + } + + } + + // END: Event3Handler1609469393 + + +} + diff --git a/src/Persistence/MartenTests/Internal/Generated/WolverineHandlers/IncrementA2Handler79726078.cs b/src/Persistence/MartenTests/Internal/Generated/WolverineHandlers/IncrementA2Handler79726078.cs new file mode 100644 index 000000000..e2ffcae04 --- /dev/null +++ b/src/Persistence/MartenTests/Internal/Generated/WolverineHandlers/IncrementA2Handler79726078.cs @@ -0,0 +1,50 @@ +// +#pragma warning disable +using Microsoft.Extensions.Logging; +using Wolverine.Marten.Publishing; + +namespace Internal.Generated.WolverineHandlers +{ + // START: IncrementA2Handler79726078 + public class IncrementA2Handler79726078 : Wolverine.Runtime.Handlers.MessageHandler + { + private readonly Wolverine.Marten.Publishing.OutboxedSessionFactory _outboxedSessionFactory; + private readonly Microsoft.Extensions.Logging.ILogger _logger; + + public IncrementA2Handler79726078(Wolverine.Marten.Publishing.OutboxedSessionFactory outboxedSessionFactory, Microsoft.Extensions.Logging.ILogger logger) + { + _outboxedSessionFactory = outboxedSessionFactory; + _logger = logger; + } + + + + public override async System.Threading.Tasks.Task HandleAsync(Wolverine.Runtime.MessageContext context, System.Threading.CancellationToken cancellation) + { + // The actual message body + var incrementA2 = (MartenTests.IncrementA2)context.Envelope.Message; + + await using var documentSession = _outboxedSessionFactory.OpenSession(context); + var eventStore = documentSession.Events; + var aggregateId = incrementA2.SelfLetteredAggregateId; + + // Loading Marten aggregate + var eventStream = await eventStore.FetchForWriting(aggregateId, cancellation).ConfigureAwait(false); + + if (eventStream.Aggregate == null) throw new Wolverine.Marten.UnknownAggregateException(typeof(MartenTests.SelfLetteredAggregate), incrementA2.SelfLetteredAggregateId); + var selfLetteredAggregate = new MartenTests.SelfLetteredAggregate(); + + // The actual message execution + var outgoing1 = eventStream.Aggregate.Handle(incrementA2, _logger); + + eventStream.AppendOne(outgoing1); + await documentSession.SaveChangesAsync(cancellation).ConfigureAwait(false); + } + + } + + // END: IncrementA2Handler79726078 + + +} + diff --git a/src/Persistence/MartenTests/Internal/Generated/WolverineHandlers/IncrementABHandler79726094.cs b/src/Persistence/MartenTests/Internal/Generated/WolverineHandlers/IncrementABHandler79726094.cs new file mode 100644 index 000000000..b9931281d --- /dev/null +++ b/src/Persistence/MartenTests/Internal/Generated/WolverineHandlers/IncrementABHandler79726094.cs @@ -0,0 +1,52 @@ +// +#pragma warning disable +using Wolverine.Marten.Publishing; + +namespace Internal.Generated.WolverineHandlers +{ + // START: IncrementABHandler79726094 + public class IncrementABHandler79726094 : Wolverine.Runtime.Handlers.MessageHandler + { + private readonly Wolverine.Marten.Publishing.OutboxedSessionFactory _outboxedSessionFactory; + + public IncrementABHandler79726094(Wolverine.Marten.Publishing.OutboxedSessionFactory outboxedSessionFactory) + { + _outboxedSessionFactory = outboxedSessionFactory; + } + + + + public override async System.Threading.Tasks.Task HandleAsync(Wolverine.Runtime.MessageContext context, System.Threading.CancellationToken cancellation) + { + // The actual message body + var incrementAB = (MartenTests.IncrementAB)context.Envelope.Message; + + await using var documentSession = _outboxedSessionFactory.OpenSession(context); + var eventStore = documentSession.Events; + var aggregateId = incrementAB.LetterAggregateId; + + // Loading Marten aggregate + var eventStream = await eventStore.FetchForExclusiveWriting(aggregateId, cancellation).ConfigureAwait(false); + + + // The actual message execution + var outgoing1 = MartenTests.SpecialLetterHandler.Handle(incrementAB, eventStream.Aggregate); + + if (outgoing1 != null) + { + + // Capturing any possible events returned from the command handlers + eventStream.AppendMany(outgoing1); + + } + + await documentSession.SaveChangesAsync(cancellation).ConfigureAwait(false); + } + + } + + // END: IncrementABHandler79726094 + + +} + diff --git a/src/Persistence/MartenTests/Internal/Generated/WolverineHandlers/IncrementAHandler1658474384.cs b/src/Persistence/MartenTests/Internal/Generated/WolverineHandlers/IncrementAHandler1658474384.cs new file mode 100644 index 000000000..67d7b91c3 --- /dev/null +++ b/src/Persistence/MartenTests/Internal/Generated/WolverineHandlers/IncrementAHandler1658474384.cs @@ -0,0 +1,46 @@ +// +#pragma warning disable +using Wolverine.Marten.Publishing; + +namespace Internal.Generated.WolverineHandlers +{ + // START: IncrementAHandler1658474384 + public class IncrementAHandler1658474384 : Wolverine.Runtime.Handlers.MessageHandler + { + private readonly Wolverine.Marten.Publishing.OutboxedSessionFactory _outboxedSessionFactory; + + public IncrementAHandler1658474384(Wolverine.Marten.Publishing.OutboxedSessionFactory outboxedSessionFactory) + { + _outboxedSessionFactory = outboxedSessionFactory; + } + + + + public override async System.Threading.Tasks.Task HandleAsync(Wolverine.Runtime.MessageContext context, System.Threading.CancellationToken cancellation) + { + // The actual message body + var incrementA = (MartenTests.IncrementA)context.Envelope.Message; + + await using var documentSession = _outboxedSessionFactory.OpenSession(context); + var eventStore = documentSession.Events; + var aggregateId = incrementA.LetterAggregateId; + + // Loading Marten aggregate + var eventStream = await eventStore.FetchForWriting(aggregateId, cancellation).ConfigureAwait(false); + + var letterAggregateHandler = new MartenTests.LetterAggregateHandler(); + + // The actual message execution + var outgoing1 = letterAggregateHandler.Handle(incrementA, eventStream.Aggregate, documentSession); + + eventStream.AppendOne(outgoing1); + await documentSession.SaveChangesAsync(cancellation).ConfigureAwait(false); + } + + } + + // END: IncrementAHandler1658474384 + + +} + diff --git a/src/Persistence/MartenTests/Internal/Generated/WolverineHandlers/IncrementB2Handler483010605.cs b/src/Persistence/MartenTests/Internal/Generated/WolverineHandlers/IncrementB2Handler483010605.cs new file mode 100644 index 000000000..275277997 --- /dev/null +++ b/src/Persistence/MartenTests/Internal/Generated/WolverineHandlers/IncrementB2Handler483010605.cs @@ -0,0 +1,47 @@ +// +#pragma warning disable +using Wolverine.Marten.Publishing; + +namespace Internal.Generated.WolverineHandlers +{ + // START: IncrementB2Handler483010605 + public class IncrementB2Handler483010605 : Wolverine.Runtime.Handlers.MessageHandler + { + private readonly Wolverine.Marten.Publishing.OutboxedSessionFactory _outboxedSessionFactory; + + public IncrementB2Handler483010605(Wolverine.Marten.Publishing.OutboxedSessionFactory outboxedSessionFactory) + { + _outboxedSessionFactory = outboxedSessionFactory; + } + + + + public override async System.Threading.Tasks.Task HandleAsync(Wolverine.Runtime.MessageContext context, System.Threading.CancellationToken cancellation) + { + // The actual message body + var incrementB2 = (MartenTests.IncrementB2)context.Envelope.Message; + + await using var documentSession = _outboxedSessionFactory.OpenSession(context); + var eventStore = documentSession.Events; + var aggregateId = incrementB2.SelfLetteredAggregateId; + + // Loading Marten aggregate + var eventStream = await eventStore.FetchForWriting(aggregateId, cancellation).ConfigureAwait(false); + + if (eventStream.Aggregate == null) throw new Wolverine.Marten.UnknownAggregateException(typeof(MartenTests.SelfLetteredAggregate), incrementB2.SelfLetteredAggregateId); + var selfLetteredAggregate = new MartenTests.SelfLetteredAggregate(); + + // The actual message execution + var outgoing1 = await eventStream.Aggregate.Handle(incrementB2).ConfigureAwait(false); + + eventStream.AppendOne(outgoing1); + await documentSession.SaveChangesAsync(cancellation).ConfigureAwait(false); + } + + } + + // END: IncrementB2Handler483010605 + + +} + diff --git a/src/Persistence/MartenTests/Internal/Generated/WolverineHandlers/IncrementBCHandler483010622.cs b/src/Persistence/MartenTests/Internal/Generated/WolverineHandlers/IncrementBCHandler483010622.cs new file mode 100644 index 000000000..a270ed67c --- /dev/null +++ b/src/Persistence/MartenTests/Internal/Generated/WolverineHandlers/IncrementBCHandler483010622.cs @@ -0,0 +1,53 @@ +// +#pragma warning disable +using Wolverine.Marten.Publishing; + +namespace Internal.Generated.WolverineHandlers +{ + // START: IncrementBCHandler483010622 + public class IncrementBCHandler483010622 : Wolverine.Runtime.Handlers.MessageHandler + { + private readonly Wolverine.Marten.Publishing.OutboxedSessionFactory _outboxedSessionFactory; + + public IncrementBCHandler483010622(Wolverine.Marten.Publishing.OutboxedSessionFactory outboxedSessionFactory) + { + _outboxedSessionFactory = outboxedSessionFactory; + } + + + + public override async System.Threading.Tasks.Task HandleAsync(Wolverine.Runtime.MessageContext context, System.Threading.CancellationToken cancellation) + { + // The actual message body + var incrementBC = (MartenTests.IncrementBC)context.Envelope.Message; + + await using var documentSession = _outboxedSessionFactory.OpenSession(context); + var eventStore = documentSession.Events; + var aggregateId = incrementBC.LetterAggregateId; + + // Loading Marten aggregate + var eventStream = await eventStore.FetchForWriting(aggregateId, incrementBC.Version, cancellation).ConfigureAwait(false); + + var letterAggregateHandler = new MartenTests.LetterAggregateHandler(); + + // The actual message execution + var outgoing1 = letterAggregateHandler.Handle(incrementBC, eventStream.Aggregate); + + if (outgoing1 != null) + { + + // Capturing any possible events returned from the command handlers + eventStream.AppendMany(outgoing1); + + } + + await documentSession.SaveChangesAsync(cancellation).ConfigureAwait(false); + } + + } + + // END: IncrementBCHandler483010622 + + +} + diff --git a/src/Persistence/MartenTests/Internal/Generated/WolverineHandlers/IncrementBHandler1255189857.cs b/src/Persistence/MartenTests/Internal/Generated/WolverineHandlers/IncrementBHandler1255189857.cs new file mode 100644 index 000000000..b7bde7438 --- /dev/null +++ b/src/Persistence/MartenTests/Internal/Generated/WolverineHandlers/IncrementBHandler1255189857.cs @@ -0,0 +1,49 @@ +// +#pragma warning disable +using Microsoft.Extensions.Logging; +using Wolverine.Marten.Publishing; + +namespace Internal.Generated.WolverineHandlers +{ + // START: IncrementBHandler1255189857 + public class IncrementBHandler1255189857 : Wolverine.Runtime.Handlers.MessageHandler + { + private readonly Wolverine.Marten.Publishing.OutboxedSessionFactory _outboxedSessionFactory; + private readonly Microsoft.Extensions.Logging.ILogger _logger; + + public IncrementBHandler1255189857(Wolverine.Marten.Publishing.OutboxedSessionFactory outboxedSessionFactory, Microsoft.Extensions.Logging.ILogger logger) + { + _outboxedSessionFactory = outboxedSessionFactory; + _logger = logger; + } + + + + public override async System.Threading.Tasks.Task HandleAsync(Wolverine.Runtime.MessageContext context, System.Threading.CancellationToken cancellation) + { + // The actual message body + var incrementB = (MartenTests.IncrementB)context.Envelope.Message; + + await using var documentSession = _outboxedSessionFactory.OpenSession(context); + var eventStore = documentSession.Events; + var aggregateId = incrementB.LetterAggregateId; + + // Loading Marten aggregate + var eventStream = await eventStore.FetchForWriting(aggregateId, cancellation).ConfigureAwait(false); + + var letterAggregateHandler = new MartenTests.LetterAggregateHandler(); + + // The actual message execution + var outgoing1 = await letterAggregateHandler.Handle(incrementB, eventStream.Aggregate, _logger).ConfigureAwait(false); + + eventStream.AppendOne(outgoing1); + await documentSession.SaveChangesAsync(cancellation).ConfigureAwait(false); + } + + } + + // END: IncrementBHandler1255189857 + + +} + diff --git a/src/Persistence/MartenTests/Internal/Generated/WolverineHandlers/IncrementCDHandler1083073314.cs b/src/Persistence/MartenTests/Internal/Generated/WolverineHandlers/IncrementCDHandler1083073314.cs new file mode 100644 index 000000000..5af373ff5 --- /dev/null +++ b/src/Persistence/MartenTests/Internal/Generated/WolverineHandlers/IncrementCDHandler1083073314.cs @@ -0,0 +1,47 @@ +// +#pragma warning disable +using Wolverine.Marten.Publishing; + +namespace Internal.Generated.WolverineHandlers +{ + // START: IncrementCDHandler1083073314 + public class IncrementCDHandler1083073314 : Wolverine.Runtime.Handlers.MessageHandler + { + private readonly Wolverine.Marten.Publishing.OutboxedSessionFactory _outboxedSessionFactory; + + public IncrementCDHandler1083073314(Wolverine.Marten.Publishing.OutboxedSessionFactory outboxedSessionFactory) + { + _outboxedSessionFactory = outboxedSessionFactory; + } + + + + public override async System.Threading.Tasks.Task HandleAsync(Wolverine.Runtime.MessageContext context, System.Threading.CancellationToken cancellation) + { + // The actual message body + var incrementCD = (MartenTests.IncrementCD)context.Envelope.Message; + + await using var documentSession = _outboxedSessionFactory.OpenSession(context); + var eventStore = documentSession.Events; + var aggregateId = incrementCD.LetterAggregateId; + + // Loading Marten aggregate + var eventStream = await eventStore.FetchForWriting(aggregateId, incrementCD.Version, cancellation).ConfigureAwait(false); + + var letterAggregateHandler = new MartenTests.LetterAggregateHandler(); + + // The actual message execution + (var outgoing1, var outgoing2) = letterAggregateHandler.Handle(incrementCD, eventStream.Aggregate); + + eventStream.AppendOne(outgoing1); + eventStream.AppendOne(outgoing2); + await documentSession.SaveChangesAsync(cancellation).ConfigureAwait(false); + } + + } + + // END: IncrementCDHandler1083073314 + + +} + diff --git a/src/Persistence/MartenTests/Internal/Generated/WolverineHandlers/IncrementCHandler1473693498.cs b/src/Persistence/MartenTests/Internal/Generated/WolverineHandlers/IncrementCHandler1473693498.cs new file mode 100644 index 000000000..005af4f00 --- /dev/null +++ b/src/Persistence/MartenTests/Internal/Generated/WolverineHandlers/IncrementCHandler1473693498.cs @@ -0,0 +1,45 @@ +// +#pragma warning disable +using Wolverine.Marten.Publishing; + +namespace Internal.Generated.WolverineHandlers +{ + // START: IncrementCHandler1473693498 + public class IncrementCHandler1473693498 : Wolverine.Runtime.Handlers.MessageHandler + { + private readonly Wolverine.Marten.Publishing.OutboxedSessionFactory _outboxedSessionFactory; + + public IncrementCHandler1473693498(Wolverine.Marten.Publishing.OutboxedSessionFactory outboxedSessionFactory) + { + _outboxedSessionFactory = outboxedSessionFactory; + } + + + + public override async System.Threading.Tasks.Task HandleAsync(Wolverine.Runtime.MessageContext context, System.Threading.CancellationToken cancellation) + { + // The actual message body + var incrementC = (MartenTests.IncrementC)context.Envelope.Message; + + await using var documentSession = _outboxedSessionFactory.OpenSession(context); + var eventStore = documentSession.Events; + var aggregateId = incrementC.LetterAggregateId; + + // Loading Marten aggregate + var eventStream = await eventStore.FetchForWriting(aggregateId, cancellation).ConfigureAwait(false); + + var letterAggregateHandler = new MartenTests.LetterAggregateHandler(); + + // The actual message execution + letterAggregateHandler.Handle(incrementC, eventStream); + + await documentSession.SaveChangesAsync(cancellation).ConfigureAwait(false); + } + + } + + // END: IncrementCHandler1473693498 + + +} + diff --git a/src/Persistence/MartenTests/Internal/Generated/WolverineHandlers/IncrementDHandler1876978025.cs b/src/Persistence/MartenTests/Internal/Generated/WolverineHandlers/IncrementDHandler1876978025.cs new file mode 100644 index 000000000..3878627c9 --- /dev/null +++ b/src/Persistence/MartenTests/Internal/Generated/WolverineHandlers/IncrementDHandler1876978025.cs @@ -0,0 +1,45 @@ +// +#pragma warning disable +using Wolverine.Marten.Publishing; + +namespace Internal.Generated.WolverineHandlers +{ + // START: IncrementDHandler1876978025 + public class IncrementDHandler1876978025 : Wolverine.Runtime.Handlers.MessageHandler + { + private readonly Wolverine.Marten.Publishing.OutboxedSessionFactory _outboxedSessionFactory; + + public IncrementDHandler1876978025(Wolverine.Marten.Publishing.OutboxedSessionFactory outboxedSessionFactory) + { + _outboxedSessionFactory = outboxedSessionFactory; + } + + + + public override async System.Threading.Tasks.Task HandleAsync(Wolverine.Runtime.MessageContext context, System.Threading.CancellationToken cancellation) + { + // The actual message body + var incrementD = (MartenTests.IncrementD)context.Envelope.Message; + + await using var documentSession = _outboxedSessionFactory.OpenSession(context); + var eventStore = documentSession.Events; + var aggregateId = incrementD.LetterAggregateId; + + // Loading Marten aggregate + var eventStream = await eventStore.FetchForWriting(aggregateId, cancellation).ConfigureAwait(false); + + var letterAggregateHandler = new MartenTests.LetterAggregateHandler(); + + // The actual message execution + await letterAggregateHandler.Handle(incrementD, eventStream).ConfigureAwait(false); + + await documentSession.SaveChangesAsync(cancellation).ConfigureAwait(false); + } + + } + + // END: IncrementDHandler1876978025 + + +} + diff --git a/src/Persistence/MartenTests/Internal/Generated/WolverineHandlers/IncrementMany2Handler448896552.cs b/src/Persistence/MartenTests/Internal/Generated/WolverineHandlers/IncrementMany2Handler448896552.cs new file mode 100644 index 000000000..92053da1f --- /dev/null +++ b/src/Persistence/MartenTests/Internal/Generated/WolverineHandlers/IncrementMany2Handler448896552.cs @@ -0,0 +1,54 @@ +// +#pragma warning disable +using Wolverine.Marten.Publishing; + +namespace Internal.Generated.WolverineHandlers +{ + // START: IncrementMany2Handler448896552 + public class IncrementMany2Handler448896552 : Wolverine.Runtime.Handlers.MessageHandler + { + private readonly Wolverine.Marten.Publishing.OutboxedSessionFactory _outboxedSessionFactory; + + public IncrementMany2Handler448896552(Wolverine.Marten.Publishing.OutboxedSessionFactory outboxedSessionFactory) + { + _outboxedSessionFactory = outboxedSessionFactory; + } + + + + public override async System.Threading.Tasks.Task HandleAsync(Wolverine.Runtime.MessageContext context, System.Threading.CancellationToken cancellation) + { + // The actual message body + var incrementMany2 = (MartenTests.IncrementMany2)context.Envelope.Message; + + await using var documentSession = _outboxedSessionFactory.OpenSession(context); + var eventStore = documentSession.Events; + var aggregateId = incrementMany2.SelfLetteredAggregateId; + + // Loading Marten aggregate + var eventStream = await eventStore.FetchForWriting(aggregateId, cancellation).ConfigureAwait(false); + + if (eventStream.Aggregate == null) throw new Wolverine.Marten.UnknownAggregateException(typeof(MartenTests.SelfLetteredAggregate), incrementMany2.SelfLetteredAggregateId); + var selfLetteredAggregate = new MartenTests.SelfLetteredAggregate(); + + // The actual message execution + var outgoing1 = eventStream.Aggregate.Handle(incrementMany2); + + if (outgoing1 != null) + { + + // Capturing any possible events returned from the command handlers + eventStream.AppendMany(outgoing1); + + } + + await documentSession.SaveChangesAsync(cancellation).ConfigureAwait(false); + } + + } + + // END: IncrementMany2Handler448896552 + + +} + diff --git a/src/Persistence/MartenTests/Internal/Generated/WolverineHandlers/IncrementManyAsyncHandler2038967698.cs b/src/Persistence/MartenTests/Internal/Generated/WolverineHandlers/IncrementManyAsyncHandler2038967698.cs new file mode 100644 index 000000000..92f977d32 --- /dev/null +++ b/src/Persistence/MartenTests/Internal/Generated/WolverineHandlers/IncrementManyAsyncHandler2038967698.cs @@ -0,0 +1,53 @@ +// +#pragma warning disable +using Wolverine.Marten.Publishing; + +namespace Internal.Generated.WolverineHandlers +{ + // START: IncrementManyAsyncHandler2038967698 + public class IncrementManyAsyncHandler2038967698 : Wolverine.Runtime.Handlers.MessageHandler + { + private readonly Wolverine.Marten.Publishing.OutboxedSessionFactory _outboxedSessionFactory; + + public IncrementManyAsyncHandler2038967698(Wolverine.Marten.Publishing.OutboxedSessionFactory outboxedSessionFactory) + { + _outboxedSessionFactory = outboxedSessionFactory; + } + + + + public override async System.Threading.Tasks.Task HandleAsync(Wolverine.Runtime.MessageContext context, System.Threading.CancellationToken cancellation) + { + // The actual message body + var incrementManyAsync = (MartenTests.IncrementManyAsync)context.Envelope.Message; + + await using var documentSession = _outboxedSessionFactory.OpenSession(context); + var eventStore = documentSession.Events; + var aggregateId = incrementManyAsync.LetterAggregateId; + + // Loading Marten aggregate + var eventStream = await eventStore.FetchForWriting(aggregateId, cancellation).ConfigureAwait(false); + + var letterAggregateHandler = new MartenTests.LetterAggregateHandler(); + + // The actual message execution + var outgoing1 = await letterAggregateHandler.Handle(incrementManyAsync, eventStream.Aggregate, documentSession).ConfigureAwait(false); + + if (outgoing1 != null) + { + + // Capturing any possible events returned from the command handlers + eventStream.AppendMany(outgoing1); + + } + + await documentSession.SaveChangesAsync(cancellation).ConfigureAwait(false); + } + + } + + // END: IncrementManyAsyncHandler2038967698 + + +} + diff --git a/src/Persistence/MartenTests/Internal/Generated/WolverineHandlers/IncrementManyHandler1569177634.cs b/src/Persistence/MartenTests/Internal/Generated/WolverineHandlers/IncrementManyHandler1569177634.cs new file mode 100644 index 000000000..09930a6f0 --- /dev/null +++ b/src/Persistence/MartenTests/Internal/Generated/WolverineHandlers/IncrementManyHandler1569177634.cs @@ -0,0 +1,53 @@ +// +#pragma warning disable +using Wolverine.Marten.Publishing; + +namespace Internal.Generated.WolverineHandlers +{ + // START: IncrementManyHandler1569177634 + public class IncrementManyHandler1569177634 : Wolverine.Runtime.Handlers.MessageHandler + { + private readonly Wolverine.Marten.Publishing.OutboxedSessionFactory _outboxedSessionFactory; + + public IncrementManyHandler1569177634(Wolverine.Marten.Publishing.OutboxedSessionFactory outboxedSessionFactory) + { + _outboxedSessionFactory = outboxedSessionFactory; + } + + + + public override async System.Threading.Tasks.Task HandleAsync(Wolverine.Runtime.MessageContext context, System.Threading.CancellationToken cancellation) + { + // The actual message body + var incrementMany = (MartenTests.IncrementMany)context.Envelope.Message; + + await using var documentSession = _outboxedSessionFactory.OpenSession(context); + var eventStore = documentSession.Events; + var aggregateId = incrementMany.LetterAggregateId; + + // Loading Marten aggregate + var eventStream = await eventStore.FetchForWriting(aggregateId, cancellation).ConfigureAwait(false); + + var letterAggregateHandler = new MartenTests.LetterAggregateHandler(); + + // The actual message execution + var outgoing1 = letterAggregateHandler.Handle(incrementMany, eventStream.Aggregate, documentSession); + + if (outgoing1 != null) + { + + // Capturing any possible events returned from the command handlers + eventStream.AppendMany(outgoing1); + + } + + await documentSession.SaveChangesAsync(cancellation).ConfigureAwait(false); + } + + } + + // END: IncrementManyHandler1569177634 + + +} + diff --git a/src/Persistence/MartenTests/Internal/Generated/WolverineHandlers/LetterMessage1Handler726704086.cs b/src/Persistence/MartenTests/Internal/Generated/WolverineHandlers/LetterMessage1Handler726704086.cs new file mode 100644 index 000000000..91b56d1f1 --- /dev/null +++ b/src/Persistence/MartenTests/Internal/Generated/WolverineHandlers/LetterMessage1Handler726704086.cs @@ -0,0 +1,29 @@ +// +#pragma warning disable + +namespace Internal.Generated.WolverineHandlers +{ + // START: LetterMessage1Handler726704086 + public class LetterMessage1Handler726704086 : Wolverine.Runtime.Handlers.MessageHandler + { + + + public override System.Threading.Tasks.Task HandleAsync(Wolverine.Runtime.MessageContext context, System.Threading.CancellationToken cancellation) + { + // The actual message body + var letterMessage1 = (MartenTests.LetterMessage1)context.Envelope.Message; + + + // The actual message execution + MartenTests.ResponseHandler.Handle(letterMessage1); + + return System.Threading.Tasks.Task.CompletedTask; + } + + } + + // END: LetterMessage1Handler726704086 + + +} + diff --git a/src/Persistence/MartenTests/Internal/Generated/WolverineHandlers/LetterMessage2Handler839379855.cs b/src/Persistence/MartenTests/Internal/Generated/WolverineHandlers/LetterMessage2Handler839379855.cs new file mode 100644 index 000000000..6b50ecd97 --- /dev/null +++ b/src/Persistence/MartenTests/Internal/Generated/WolverineHandlers/LetterMessage2Handler839379855.cs @@ -0,0 +1,29 @@ +// +#pragma warning disable + +namespace Internal.Generated.WolverineHandlers +{ + // START: LetterMessage2Handler839379855 + public class LetterMessage2Handler839379855 : Wolverine.Runtime.Handlers.MessageHandler + { + + + public override System.Threading.Tasks.Task HandleAsync(Wolverine.Runtime.MessageContext context, System.Threading.CancellationToken cancellation) + { + // The actual message body + var letterMessage2 = (MartenTests.LetterMessage2)context.Envelope.Message; + + + // The actual message execution + MartenTests.ResponseHandler.Handle(letterMessage2); + + return System.Threading.Tasks.Task.CompletedTask; + } + + } + + // END: LetterMessage2Handler839379855 + + +} + diff --git a/src/Persistence/MartenTests/Internal/Generated/WolverineHandlers/Outgoing1Handler1264108911.cs b/src/Persistence/MartenTests/Internal/Generated/WolverineHandlers/Outgoing1Handler1264108911.cs new file mode 100644 index 000000000..76d510674 --- /dev/null +++ b/src/Persistence/MartenTests/Internal/Generated/WolverineHandlers/Outgoing1Handler1264108911.cs @@ -0,0 +1,29 @@ +// +#pragma warning disable + +namespace Internal.Generated.WolverineHandlers +{ + // START: Outgoing1Handler1264108911 + public class Outgoing1Handler1264108911 : Wolverine.Runtime.Handlers.MessageHandler + { + + + public override System.Threading.Tasks.Task HandleAsync(Wolverine.Runtime.MessageContext context, System.Threading.CancellationToken cancellation) + { + // The actual message body + var outgoing1 = (MartenTests.Outgoing1)context.Envelope.Message; + + + // The actual message execution + MartenTests.Outgoing1Handler.Handle(outgoing1); + + return System.Threading.Tasks.Task.CompletedTask; + } + + } + + // END: Outgoing1Handler1264108911 + + +} + diff --git a/src/Persistence/MartenTests/Internal/Generated/WolverineHandlers/RaiseAAAHandler1649029811.cs b/src/Persistence/MartenTests/Internal/Generated/WolverineHandlers/RaiseAAAHandler1649029811.cs new file mode 100644 index 000000000..4a042b060 --- /dev/null +++ b/src/Persistence/MartenTests/Internal/Generated/WolverineHandlers/RaiseAAAHandler1649029811.cs @@ -0,0 +1,48 @@ +// +#pragma warning disable +using Wolverine.Marten.Publishing; + +namespace Internal.Generated.WolverineHandlers +{ + // START: RaiseAAAHandler1649029811 + public class RaiseAAAHandler1649029811 : Wolverine.Runtime.Handlers.MessageHandler + { + private readonly Wolverine.Marten.Publishing.OutboxedSessionFactory _outboxedSessionFactory; + + public RaiseAAAHandler1649029811(Wolverine.Marten.Publishing.OutboxedSessionFactory outboxedSessionFactory) + { + _outboxedSessionFactory = outboxedSessionFactory; + } + + + + public override async System.Threading.Tasks.Task HandleAsync(Wolverine.Runtime.MessageContext context, System.Threading.CancellationToken cancellation) + { + // The actual message body + var raiseAAA = (MartenTests.RaiseAAA)context.Envelope.Message; + + await using var documentSession = _outboxedSessionFactory.OpenSession(context); + var eventStore = documentSession.Events; + var aggregateId = raiseAAA.LetterAggregateId; + + // Loading Marten aggregate + var eventStream = await eventStore.FetchForWriting(aggregateId, cancellation).ConfigureAwait(false); + + + // The actual message execution + var outgoing1 = MartenTests.RaiseLetterHandler.Handle(raiseAAA, eventStream); + + + // Outgoing, cascaded message + await context.EnqueueCascadingAsync(outgoing1).ConfigureAwait(false); + + await documentSession.SaveChangesAsync(cancellation).ConfigureAwait(false); + } + + } + + // END: RaiseAAAHandler1649029811 + + +} + diff --git a/src/Persistence/MartenTests/Internal/Generated/WolverineHandlers/RaiseAABCCHandler1413048758.cs b/src/Persistence/MartenTests/Internal/Generated/WolverineHandlers/RaiseAABCCHandler1413048758.cs new file mode 100644 index 000000000..2855d7e4c --- /dev/null +++ b/src/Persistence/MartenTests/Internal/Generated/WolverineHandlers/RaiseAABCCHandler1413048758.cs @@ -0,0 +1,56 @@ +// +#pragma warning disable +using Wolverine.Marten.Publishing; + +namespace Internal.Generated.WolverineHandlers +{ + // START: RaiseAABCCHandler1413048758 + public class RaiseAABCCHandler1413048758 : Wolverine.Runtime.Handlers.MessageHandler + { + private readonly Wolverine.Marten.Publishing.OutboxedSessionFactory _outboxedSessionFactory; + + public RaiseAABCCHandler1413048758(Wolverine.Marten.Publishing.OutboxedSessionFactory outboxedSessionFactory) + { + _outboxedSessionFactory = outboxedSessionFactory; + } + + + + public override async System.Threading.Tasks.Task HandleAsync(Wolverine.Runtime.MessageContext context, System.Threading.CancellationToken cancellation) + { + // The actual message body + var raiseAABCC = (MartenTests.RaiseAABCC)context.Envelope.Message; + + await using var documentSession = _outboxedSessionFactory.OpenSession(context); + var eventStore = documentSession.Events; + var aggregateId = raiseAABCC.LetterAggregateId; + + // Loading Marten aggregate + var eventStream = await eventStore.FetchForWriting(aggregateId, cancellation).ConfigureAwait(false); + + + // The actual message execution + (var outgoing1, var outgoing2) = MartenTests.RaiseLetterHandler.Handle(raiseAABCC, eventStream.Aggregate); + + + // Outgoing, cascaded message + await context.EnqueueCascadingAsync(outgoing1).ConfigureAwait(false); + + if (outgoing2 != null) + { + + // Capturing any possible events returned from the command handlers + eventStream.AppendMany(outgoing2); + + } + + await documentSession.SaveChangesAsync(cancellation).ConfigureAwait(false); + } + + } + + // END: RaiseAABCCHandler1413048758 + + +} + diff --git a/src/Persistence/MartenTests/Internal/Generated/WolverineHandlers/RaiseABCHandler1483138068.cs b/src/Persistence/MartenTests/Internal/Generated/WolverineHandlers/RaiseABCHandler1483138068.cs new file mode 100644 index 000000000..4115246fd --- /dev/null +++ b/src/Persistence/MartenTests/Internal/Generated/WolverineHandlers/RaiseABCHandler1483138068.cs @@ -0,0 +1,56 @@ +// +#pragma warning disable +using Wolverine.Marten.Publishing; + +namespace Internal.Generated.WolverineHandlers +{ + // START: RaiseABCHandler1483138068 + public class RaiseABCHandler1483138068 : Wolverine.Runtime.Handlers.MessageHandler + { + private readonly Wolverine.Marten.Publishing.OutboxedSessionFactory _outboxedSessionFactory; + + public RaiseABCHandler1483138068(Wolverine.Marten.Publishing.OutboxedSessionFactory outboxedSessionFactory) + { + _outboxedSessionFactory = outboxedSessionFactory; + } + + + + public override async System.Threading.Tasks.Task HandleAsync(Wolverine.Runtime.MessageContext context, System.Threading.CancellationToken cancellation) + { + // The actual message body + var raiseABC = (MartenTests.RaiseABC)context.Envelope.Message; + + await using var documentSession = _outboxedSessionFactory.OpenSession(context); + var eventStore = documentSession.Events; + var aggregateId = raiseABC.LetterAggregateId; + + // Loading Marten aggregate + var eventStream = await eventStore.FetchForWriting(aggregateId, cancellation).ConfigureAwait(false); + + + // The actual message execution + (var outgoing1, var outgoing2) = MartenTests.RaiseLetterHandler.Handle(raiseABC, eventStream.Aggregate); + + if (outgoing1 != null) + { + + // Capturing any possible events returned from the command handlers + eventStream.AppendMany(outgoing1); + + } + + + // Outgoing, cascaded message + await context.EnqueueCascadingAsync(outgoing2).ConfigureAwait(false); + + await documentSession.SaveChangesAsync(cancellation).ConfigureAwait(false); + } + + } + + // END: RaiseABCHandler1483138068 + + +} + diff --git a/src/Persistence/MartenTests/Internal/Generated/WolverineHandlers/RaiseBBCCCHandler1900945687.cs b/src/Persistence/MartenTests/Internal/Generated/WolverineHandlers/RaiseBBCCCHandler1900945687.cs new file mode 100644 index 000000000..25b27a6ee --- /dev/null +++ b/src/Persistence/MartenTests/Internal/Generated/WolverineHandlers/RaiseBBCCCHandler1900945687.cs @@ -0,0 +1,60 @@ +// +#pragma warning disable +using Wolverine.Marten.Publishing; + +namespace Internal.Generated.WolverineHandlers +{ + // START: RaiseBBCCCHandler1900945687 + public class RaiseBBCCCHandler1900945687 : Wolverine.Runtime.Handlers.MessageHandler + { + private readonly Wolverine.Marten.Publishing.OutboxedSessionFactory _outboxedSessionFactory; + + public RaiseBBCCCHandler1900945687(Wolverine.Marten.Publishing.OutboxedSessionFactory outboxedSessionFactory) + { + _outboxedSessionFactory = outboxedSessionFactory; + } + + + + public override async System.Threading.Tasks.Task HandleAsync(Wolverine.Runtime.MessageContext context, System.Threading.CancellationToken cancellation) + { + // The actual message body + var raiseBBCCC = (MartenTests.RaiseBBCCC)context.Envelope.Message; + + await using var documentSession = _outboxedSessionFactory.OpenSession(context); + var eventStore = documentSession.Events; + var aggregateId = raiseBBCCC.LetterAggregateId; + + // Loading Marten aggregate + var eventStream = await eventStore.FetchForWriting(aggregateId, cancellation).ConfigureAwait(false); + + + // The actual message execution + (var outgoing1, var outgoing2, var outgoing3) = MartenTests.RaiseLetterHandler.Handle(raiseBBCCC, eventStream.Aggregate); + + + // Outgoing, cascaded message + await context.EnqueueCascadingAsync(outgoing1).ConfigureAwait(false); + + if (outgoing2 != null) + { + + // Capturing any possible events returned from the command handlers + eventStream.AppendMany(outgoing2); + + } + + + // Outgoing, cascaded message + await context.EnqueueCascadingAsync(outgoing3).ConfigureAwait(false); + + await documentSession.SaveChangesAsync(cancellation).ConfigureAwait(false); + } + + } + + // END: RaiseBBCCCHandler1900945687 + + +} + diff --git a/src/Persistence/MartenTests/Internal/Generated/WolverineHandlers/RaiseHandler985277900.cs b/src/Persistence/MartenTests/Internal/Generated/WolverineHandlers/RaiseHandler985277900.cs new file mode 100644 index 000000000..30584d0f9 --- /dev/null +++ b/src/Persistence/MartenTests/Internal/Generated/WolverineHandlers/RaiseHandler985277900.cs @@ -0,0 +1,61 @@ +// +#pragma warning disable +using Wolverine.Marten.Publishing; + +namespace Internal.Generated.WolverineHandlers +{ + // START: RaiseHandler985277900 + public class RaiseHandler985277900 : Wolverine.Runtime.Handlers.MessageHandler + { + private readonly Wolverine.Marten.Publishing.OutboxedSessionFactory _outboxedSessionFactory; + + public RaiseHandler985277900(Wolverine.Marten.Publishing.OutboxedSessionFactory outboxedSessionFactory) + { + _outboxedSessionFactory = outboxedSessionFactory; + } + + + + public override async System.Threading.Tasks.Task HandleAsync(Wolverine.Runtime.MessageContext context, System.Threading.CancellationToken cancellation) + { + // The actual message body + var raise = (MartenTests.Raise)context.Envelope.Message; + + await using var documentSession = _outboxedSessionFactory.OpenSession(context); + var eventStore = documentSession.Events; + var aggregateId = raise.LetterAggregateId; + + // Loading Marten aggregate + var eventStream = await eventStore.FetchForWriting(aggregateId, cancellation).ConfigureAwait(false); + + + // The actual message execution + (var outgoing1, var outgoing2) = MartenTests.RaiseLetterHandler.Handle(raise, eventStream.Aggregate); + + + // Outgoing, cascaded message + await context.EnqueueCascadingAsync(outgoing1).ConfigureAwait(false); + + if (outgoing2 != null) + { + + // Capturing any possible events returned from the command handlers + eventStream.AppendMany(outgoing2); + + } + + await documentSession.SaveChangesAsync(cancellation).ConfigureAwait(false); + var response_of_letterAggregate = await eventStore.FetchLatest(aggregateId, cancellation); + + // Outgoing, cascaded message + await context.EnqueueCascadingAsync(response_of_letterAggregate).ConfigureAwait(false); + + } + + } + + // END: RaiseHandler985277900 + + +} + diff --git a/src/Persistence/MartenTests/Internal/Generated/WolverineHandlers/RaiseIfValidatedHandler2071345539.cs b/src/Persistence/MartenTests/Internal/Generated/WolverineHandlers/RaiseIfValidatedHandler2071345539.cs new file mode 100644 index 000000000..f0c1ee1d7 --- /dev/null +++ b/src/Persistence/MartenTests/Internal/Generated/WolverineHandlers/RaiseIfValidatedHandler2071345539.cs @@ -0,0 +1,55 @@ +// +#pragma warning disable +using Wolverine.Marten.Publishing; + +namespace Internal.Generated.WolverineHandlers +{ + // START: RaiseIfValidatedHandler2071345539 + public class RaiseIfValidatedHandler2071345539 : Wolverine.Runtime.Handlers.MessageHandler + { + private readonly Wolverine.Marten.Publishing.OutboxedSessionFactory _outboxedSessionFactory; + + public RaiseIfValidatedHandler2071345539(Wolverine.Marten.Publishing.OutboxedSessionFactory outboxedSessionFactory) + { + _outboxedSessionFactory = outboxedSessionFactory; + } + + + + public override async System.Threading.Tasks.Task HandleAsync(Wolverine.Runtime.MessageContext context, System.Threading.CancellationToken cancellation) + { + // The actual message body + var raiseIfValidated = (MartenTests.RaiseIfValidated)context.Envelope.Message; + + await using var documentSession = _outboxedSessionFactory.OpenSession(context); + var eventStore = documentSession.Events; + var aggregateId = raiseIfValidated.LetterAggregateId; + + // Loading Marten aggregate + var eventStream = await eventStore.FetchForWriting(aggregateId, cancellation).ConfigureAwait(false); + + var result_of_Validate1 = MartenTests.RaiseIfValidatedHandler.Validate(eventStream.Aggregate); + // Evaluate whether or not the execution should stop based on the HandlerContinuation value + if (result_of_Validate1 == Wolverine.HandlerContinuation.Stop) return; + + // The actual message execution + var outgoing1 = MartenTests.RaiseIfValidatedHandler.Handle(raiseIfValidated, eventStream.Aggregate); + + if (outgoing1 != null) + { + + // Capturing any possible events returned from the command handlers + eventStream.AppendMany(outgoing1); + + } + + await documentSession.SaveChangesAsync(cancellation).ConfigureAwait(false); + } + + } + + // END: RaiseIfValidatedHandler2071345539 + + +} + diff --git a/src/Persistence/MartenTests/Internal/Generated/WolverineHandlers/RaiseLotsAsyncHandler89313884.cs b/src/Persistence/MartenTests/Internal/Generated/WolverineHandlers/RaiseLotsAsyncHandler89313884.cs new file mode 100644 index 000000000..75a011399 --- /dev/null +++ b/src/Persistence/MartenTests/Internal/Generated/WolverineHandlers/RaiseLotsAsyncHandler89313884.cs @@ -0,0 +1,46 @@ +// +#pragma warning disable +using Wolverine.Marten.Publishing; + +namespace Internal.Generated.WolverineHandlers +{ + // START: RaiseLotsAsyncHandler89313884 + public class RaiseLotsAsyncHandler89313884 : Wolverine.Runtime.Handlers.MessageHandler + { + private readonly Wolverine.Marten.Publishing.OutboxedSessionFactory _outboxedSessionFactory; + + public RaiseLotsAsyncHandler89313884(Wolverine.Marten.Publishing.OutboxedSessionFactory outboxedSessionFactory) + { + _outboxedSessionFactory = outboxedSessionFactory; + } + + + + public override async System.Threading.Tasks.Task HandleAsync(Wolverine.Runtime.MessageContext context, System.Threading.CancellationToken cancellation) + { + // The actual message body + var raiseLotsAsync = (MartenTests.RaiseLotsAsync)context.Envelope.Message; + + await using var documentSession = _outboxedSessionFactory.OpenSession(context); + var eventStore = documentSession.Events; + var aggregateId = raiseLotsAsync.LetterAggregateId; + + // Loading Marten aggregate + var eventStream = await eventStore.FetchForWriting(aggregateId, cancellation).ConfigureAwait(false); + + + // The actual message execution + var outgoing1 = MartenTests.RaiseLetterHandler.Handle(raiseLotsAsync, eventStream.Aggregate); + + // Apply events to Marten event stream + await foreach (var letterAggregateEvent in outgoing1) eventStream.AppendOne(letterAggregateEvent); + await documentSession.SaveChangesAsync(cancellation).ConfigureAwait(false); + } + + } + + // END: RaiseLotsAsyncHandler89313884 + + +} + diff --git a/src/Persistence/MartenTests/Internal/Generated/WolverineHandlers/RaiseOnlyDHandler1609388090.cs b/src/Persistence/MartenTests/Internal/Generated/WolverineHandlers/RaiseOnlyDHandler1609388090.cs new file mode 100644 index 000000000..167aa9efb --- /dev/null +++ b/src/Persistence/MartenTests/Internal/Generated/WolverineHandlers/RaiseOnlyDHandler1609388090.cs @@ -0,0 +1,45 @@ +// +#pragma warning disable +using Wolverine.Marten.Publishing; + +namespace Internal.Generated.WolverineHandlers +{ + // START: RaiseOnlyDHandler1609388090 + public class RaiseOnlyDHandler1609388090 : Wolverine.Runtime.Handlers.MessageHandler + { + private readonly Wolverine.Marten.Publishing.OutboxedSessionFactory _outboxedSessionFactory; + + public RaiseOnlyDHandler1609388090(Wolverine.Marten.Publishing.OutboxedSessionFactory outboxedSessionFactory) + { + _outboxedSessionFactory = outboxedSessionFactory; + } + + + + public override async System.Threading.Tasks.Task HandleAsync(Wolverine.Runtime.MessageContext context, System.Threading.CancellationToken cancellation) + { + // The actual message body + var raiseOnlyD = (MartenTests.RaiseOnlyD)context.Envelope.Message; + + await using var documentSession = _outboxedSessionFactory.OpenSession(context); + var eventStore = documentSession.Events; + var aggregateId = raiseOnlyD.LetterAggregateId; + + // Loading Marten aggregate + var eventStream = await eventStore.FetchForWriting(aggregateId, cancellation).ConfigureAwait(false); + + + // The actual message execution + var outgoing1 = MartenTests.RaiseLetterHandler.Handle(raiseOnlyD, eventStream.Aggregate); + + eventStream.AppendOne(outgoing1); + await documentSession.SaveChangesAsync(cancellation).ConfigureAwait(false); + } + + } + + // END: RaiseOnlyDHandler1609388090 + + +} + diff --git a/src/Persistence/MartenTests/Internal/Generated/WolverineHandlers/ResponseHandler2107844337.cs b/src/Persistence/MartenTests/Internal/Generated/WolverineHandlers/ResponseHandler2107844337.cs new file mode 100644 index 000000000..36b30592b --- /dev/null +++ b/src/Persistence/MartenTests/Internal/Generated/WolverineHandlers/ResponseHandler2107844337.cs @@ -0,0 +1,29 @@ +// +#pragma warning disable + +namespace Internal.Generated.WolverineHandlers +{ + // START: ResponseHandler2107844337 + public class ResponseHandler2107844337 : Wolverine.Runtime.Handlers.MessageHandler + { + + + public override System.Threading.Tasks.Task HandleAsync(Wolverine.Runtime.MessageContext context, System.Threading.CancellationToken cancellation) + { + // The actual message body + var response = (MartenTests.Response)context.Envelope.Message; + + + // The actual message execution + MartenTests.ResponseHandler.Handle(response); + + return System.Threading.Tasks.Task.CompletedTask; + } + + } + + // END: ResponseHandler2107844337 + + +} + diff --git a/src/Persistence/MartenTests/handler_actions_with_implied_marten_operations.cs b/src/Persistence/MartenTests/handler_actions_with_implied_marten_operations.cs index 85473c0cc..8b0526791 100644 --- a/src/Persistence/MartenTests/handler_actions_with_implied_marten_operations.cs +++ b/src/Persistence/MartenTests/handler_actions_with_implied_marten_operations.cs @@ -97,6 +97,20 @@ public async Task delete_document() var doc = await session.LoadAsync("Max"); doc.ShouldBeNull(); } + + [Fact] + public async Task use_enumerable_of_imartenop_as_return_value() + { + await _store.Advanced.Clean.DeleteDocumentsByTypeAsync(typeof(NamedDocument)); + + await _host.InvokeMessageAndWaitAsync(new AppendManyNamedDocuments(["red", "blue", "green"])); + + using var session = _store.LightweightSession(); + + (await session.LoadAsync("red")).Number.ShouldBe(1); + (await session.LoadAsync("blue")).Number.ShouldBe(2); + (await session.LoadAsync("green")).Number.ShouldBe(3); + } } public record CreateMartenDocument(string Name); @@ -148,6 +162,25 @@ public static void Handle(MartenMessage2 message) } } +public record AppendManyNamedDocuments(string[] Names); + +public static class AppendManyNamedDocumentsHandler +{ + #region sample_using_ienumerable_of_martenop_as_side_effect + + // Just keep in mind that this "example" was rigged up for test coverage + public static IEnumerable Handle(AppendManyNamedDocuments command) + { + var number = 1; + foreach (var name in command.Names) + { + yield return MartenOps.Store(new NamedDocument{Id = name, Number = number++}); + } + } + + #endregion +} + public class NamedDocument { public string Id { get; set; } diff --git a/src/Persistence/MartenTests/transactional_frame_end_to_end.cs b/src/Persistence/MartenTests/transactional_frame_end_to_end.cs index 14ee1ab95..61f1fc96a 100644 --- a/src/Persistence/MartenTests/transactional_frame_end_to_end.cs +++ b/src/Persistence/MartenTests/transactional_frame_end_to_end.cs @@ -93,7 +93,7 @@ public void Apply(IReadOnlyList chains, GenerationRules rules, ISe // for each chain chains .Where(chain => chain.MessageType.Name.EndsWith("Command")) - .Each(chain => chain.Middleware.Add(new TransactionalFrame(chain))); + .Each(chain => chain.Middleware.Add(new CreateDocumentSessionFrame(chain))); } } diff --git a/src/Persistence/MartenTests/using_storage_return_types_and_entity_attributes.cs b/src/Persistence/MartenTests/using_storage_return_types_and_entity_attributes.cs new file mode 100644 index 000000000..59082865a --- /dev/null +++ b/src/Persistence/MartenTests/using_storage_return_types_and_entity_attributes.cs @@ -0,0 +1,38 @@ +using IntegrationTests; +using Marten; +using Wolverine; +using Wolverine.ComplianceTests; +using Wolverine.Marten; + +namespace MartenTests; + +public class using_storage_return_types_and_entity_attributes : StorageActionCompliance +{ + protected override void configureWolverine(WolverineOptions opts) + { + opts.Services.AddMarten(m => + { + m.Connection(Servers.PostgresConnectionString); + m.DatabaseSchemaName = "todos"; + m.DisableNpgsqlLogging = true; + }).IntegrateWithWolverine(); + + opts.Policies.AutoApplyTransactions(); + } + + public override async Task Load(string id) + { + var store = Host.DocumentStore(); + await using var session = store.QuerySession(); + return await session.LoadAsync(id); + } + + public override async Task Persist(Todo todo) + { + var store = Host.DocumentStore(); + await using var session = store.LightweightSession(); + session.Store(todo); + await session.SaveChangesAsync(); + } +} + diff --git a/src/Persistence/RavenDbTests/Code.cs b/src/Persistence/RavenDbTests/Code.cs new file mode 100644 index 000000000..8ff1f50cf --- /dev/null +++ b/src/Persistence/RavenDbTests/Code.cs @@ -0,0 +1,53 @@ +// +#pragma warning disable +using Raven.Client.Documents; + +namespace Internal.Generated.WolverineHandlers +{ + // START: CreateTodoHandler1536167811 + public class CreateTodoHandler1536167811 : Wolverine.Runtime.Handlers.MessageHandler + { + private readonly Raven.Client.Documents.IDocumentStore _documentStore; + + public CreateTodoHandler1536167811(Raven.Client.Documents.IDocumentStore documentStore) + { + _documentStore = documentStore; + } + + + + public override async System.Threading.Tasks.Task HandleAsync(Wolverine.Runtime.MessageContext context, System.Threading.CancellationToken cancellation) + { + // The actual message body + var createTodo = (Wolverine.ComplianceTests.CreateTodo)context.Envelope.Message; + + + // Open a new document session + // message context to support the outbox functionality + using var asyncDocumentSession = _documentStore.OpenAsyncSession(); + context.EnlistInOutbox(new Wolverine.RavenDb.Internals.RavenDbEnvelopeTransaction(asyncDocumentSession, context)); + + // The actual message execution + var outgoing1 = Wolverine.ComplianceTests.TodoHandler.Handle(createTodo); + + if (outgoing1 != null) + { + await asyncDocumentSession.StoreAsync(outgoing1.Entity, cancellation).ConfigureAwait(false); + } + + + // Commit any outstanding RavenDb changes + await asyncDocumentSession.SaveChangesAsync(cancellation).ConfigureAwait(false); + + + // Have to flush outgoing messages just in case Marten did nothing because of https://github.com/JasperFx/wolverine/issues/536 + await context.FlushOutgoingMessagesAsync().ConfigureAwait(false); + + } + + } + + // END: CreateTodoHandler1536167811 + + +} \ No newline at end of file diff --git a/src/Persistence/RavenDbTests/Internal/Generated/WolverineHandlers/CompleteFourHandler1230864511.cs b/src/Persistence/RavenDbTests/Internal/Generated/WolverineHandlers/CompleteFourHandler1230864511.cs index 2d578dbb1..168eb192f 100644 --- a/src/Persistence/RavenDbTests/Internal/Generated/WolverineHandlers/CompleteFourHandler1230864511.cs +++ b/src/Persistence/RavenDbTests/Internal/Generated/WolverineHandlers/CompleteFourHandler1230864511.cs @@ -18,16 +18,10 @@ public CompleteFourHandler1230864511(Raven.Client.Documents.IDocumentStore docum public override async System.Threading.Tasks.Task HandleAsync(Wolverine.Runtime.MessageContext context, System.Threading.CancellationToken cancellation) { + using var asyncDocumentSession = _documentStore.OpenAsyncSession(); // The actual message body var completeFour = (Wolverine.ComplianceTests.Sagas.CompleteFour)context.Envelope.Message; - - // Open a new document session - // message context to support the outbox functionality - using var asyncDocumentSession = _documentStore.OpenAsyncSession(); - context.EnlistInOutbox(new Wolverine.RavenDb.Internals.RavenDbEnvelopeTransaction(asyncDocumentSession, context)); - // Use optimistic concurrency for sagas - asyncDocumentSession.Advanced.UseOptimisticConcurrency = true; var sagaId = context.Envelope.SagaId; if (string.IsNullOrEmpty(sagaId)) throw new Wolverine.Persistence.Sagas.IndeterminateSagaStateIdException(context.Envelope); diff --git a/src/Persistence/RavenDbTests/Internal/Generated/WolverineHandlers/CompleteOneHandler1612253335.cs b/src/Persistence/RavenDbTests/Internal/Generated/WolverineHandlers/CompleteOneHandler1612253335.cs index 4d74ad367..91c1c8854 100644 --- a/src/Persistence/RavenDbTests/Internal/Generated/WolverineHandlers/CompleteOneHandler1612253335.cs +++ b/src/Persistence/RavenDbTests/Internal/Generated/WolverineHandlers/CompleteOneHandler1612253335.cs @@ -18,16 +18,10 @@ public CompleteOneHandler1612253335(Raven.Client.Documents.IDocumentStore docume public override async System.Threading.Tasks.Task HandleAsync(Wolverine.Runtime.MessageContext context, System.Threading.CancellationToken cancellation) { + using var asyncDocumentSession = _documentStore.OpenAsyncSession(); // The actual message body var completeOne = (Wolverine.ComplianceTests.Sagas.CompleteOne)context.Envelope.Message; - - // Open a new document session - // message context to support the outbox functionality - using var asyncDocumentSession = _documentStore.OpenAsyncSession(); - context.EnlistInOutbox(new Wolverine.RavenDb.Internals.RavenDbEnvelopeTransaction(asyncDocumentSession, context)); - // Use optimistic concurrency for sagas - asyncDocumentSession.Advanced.UseOptimisticConcurrency = true; var sagaId = context.Envelope.SagaId; if (string.IsNullOrEmpty(sagaId)) throw new Wolverine.Persistence.Sagas.IndeterminateSagaStateIdException(context.Envelope); diff --git a/src/Persistence/RavenDbTests/Internal/Generated/WolverineHandlers/CompleteTwoHandler402398939.cs b/src/Persistence/RavenDbTests/Internal/Generated/WolverineHandlers/CompleteTwoHandler402398939.cs index f3cf80810..40ef683cd 100644 --- a/src/Persistence/RavenDbTests/Internal/Generated/WolverineHandlers/CompleteTwoHandler402398939.cs +++ b/src/Persistence/RavenDbTests/Internal/Generated/WolverineHandlers/CompleteTwoHandler402398939.cs @@ -18,16 +18,10 @@ public CompleteTwoHandler402398939(Raven.Client.Documents.IDocumentStore documen public override async System.Threading.Tasks.Task HandleAsync(Wolverine.Runtime.MessageContext context, System.Threading.CancellationToken cancellation) { + using var asyncDocumentSession = _documentStore.OpenAsyncSession(); // The actual message body var completeTwo = (Wolverine.ComplianceTests.Sagas.CompleteTwo)context.Envelope.Message; - - // Open a new document session - // message context to support the outbox functionality - using var asyncDocumentSession = _documentStore.OpenAsyncSession(); - context.EnlistInOutbox(new Wolverine.RavenDb.Internals.RavenDbEnvelopeTransaction(asyncDocumentSession, context)); - // Use optimistic concurrency for sagas - asyncDocumentSession.Advanced.UseOptimisticConcurrency = true; var sagaId = context.Envelope.SagaId; if (string.IsNullOrEmpty(sagaId)) throw new Wolverine.Persistence.Sagas.IndeterminateSagaStateIdException(context.Envelope); diff --git a/src/Persistence/RavenDbTests/Internal/Generated/WolverineHandlers/FinishItAllHandler1534262635.cs b/src/Persistence/RavenDbTests/Internal/Generated/WolverineHandlers/FinishItAllHandler1534262635.cs index 5b3dfd79f..9a7f31d26 100644 --- a/src/Persistence/RavenDbTests/Internal/Generated/WolverineHandlers/FinishItAllHandler1534262635.cs +++ b/src/Persistence/RavenDbTests/Internal/Generated/WolverineHandlers/FinishItAllHandler1534262635.cs @@ -18,16 +18,10 @@ public FinishItAllHandler1534262635(Raven.Client.Documents.IDocumentStore docume public override async System.Threading.Tasks.Task HandleAsync(Wolverine.Runtime.MessageContext context, System.Threading.CancellationToken cancellation) { + using var asyncDocumentSession = _documentStore.OpenAsyncSession(); // The actual message body var finishItAll = (Wolverine.ComplianceTests.Sagas.FinishItAll)context.Envelope.Message; - - // Open a new document session - // message context to support the outbox functionality - using var asyncDocumentSession = _documentStore.OpenAsyncSession(); - context.EnlistInOutbox(new Wolverine.RavenDb.Internals.RavenDbEnvelopeTransaction(asyncDocumentSession, context)); - // Use optimistic concurrency for sagas - asyncDocumentSession.Advanced.UseOptimisticConcurrency = true; var sagaId = context.Envelope.SagaId; if (string.IsNullOrEmpty(sagaId)) throw new Wolverine.Persistence.Sagas.IndeterminateSagaStateIdException(context.Envelope); diff --git a/src/Persistence/RavenDbTests/Internal/Generated/WolverineHandlers/StringCompleteThreeHandler606415888.cs b/src/Persistence/RavenDbTests/Internal/Generated/WolverineHandlers/StringCompleteThreeHandler606415888.cs index 64c7c6c24..3c37d675f 100644 --- a/src/Persistence/RavenDbTests/Internal/Generated/WolverineHandlers/StringCompleteThreeHandler606415888.cs +++ b/src/Persistence/RavenDbTests/Internal/Generated/WolverineHandlers/StringCompleteThreeHandler606415888.cs @@ -18,16 +18,10 @@ public StringCompleteThreeHandler606415888(Raven.Client.Documents.IDocumentStore public override async System.Threading.Tasks.Task HandleAsync(Wolverine.Runtime.MessageContext context, System.Threading.CancellationToken cancellation) { + using var asyncDocumentSession = _documentStore.OpenAsyncSession(); // The actual message body var stringCompleteThree = (Wolverine.ComplianceTests.Sagas.StringCompleteThree)context.Envelope.Message; - - // Open a new document session - // message context to support the outbox functionality - using var asyncDocumentSession = _documentStore.OpenAsyncSession(); - context.EnlistInOutbox(new Wolverine.RavenDb.Internals.RavenDbEnvelopeTransaction(asyncDocumentSession, context)); - // Use optimistic concurrency for sagas - asyncDocumentSession.Advanced.UseOptimisticConcurrency = true; string sagaId = context.Envelope.SagaId ?? stringCompleteThree.SagaId; if (string.IsNullOrEmpty(sagaId)) throw new Wolverine.Persistence.Sagas.IndeterminateSagaStateIdException(context.Envelope); diff --git a/src/Persistence/RavenDbTests/Internal/Generated/WolverineHandlers/StringDoThreeHandler1820069266.cs b/src/Persistence/RavenDbTests/Internal/Generated/WolverineHandlers/StringDoThreeHandler1820069266.cs index 6268f4321..7cae05ebb 100644 --- a/src/Persistence/RavenDbTests/Internal/Generated/WolverineHandlers/StringDoThreeHandler1820069266.cs +++ b/src/Persistence/RavenDbTests/Internal/Generated/WolverineHandlers/StringDoThreeHandler1820069266.cs @@ -18,16 +18,10 @@ public StringDoThreeHandler1820069266(Raven.Client.Documents.IDocumentStore docu public override async System.Threading.Tasks.Task HandleAsync(Wolverine.Runtime.MessageContext context, System.Threading.CancellationToken cancellation) { + using var asyncDocumentSession = _documentStore.OpenAsyncSession(); // The actual message body var stringDoThree = (Wolverine.ComplianceTests.Sagas.StringDoThree)context.Envelope.Message; - - // Open a new document session - // message context to support the outbox functionality - using var asyncDocumentSession = _documentStore.OpenAsyncSession(); - context.EnlistInOutbox(new Wolverine.RavenDb.Internals.RavenDbEnvelopeTransaction(asyncDocumentSession, context)); - // Use optimistic concurrency for sagas - asyncDocumentSession.Advanced.UseOptimisticConcurrency = true; string sagaId = context.Envelope.SagaId ?? stringDoThree.TheSagaId; if (string.IsNullOrEmpty(sagaId)) throw new Wolverine.Persistence.Sagas.IndeterminateSagaStateIdException(context.Envelope); diff --git a/src/Persistence/RavenDbTests/Internal/Generated/WolverineHandlers/StringStartHandler2085759971.cs b/src/Persistence/RavenDbTests/Internal/Generated/WolverineHandlers/StringStartHandler2085759971.cs index 29fe898bb..081e5b1a8 100644 --- a/src/Persistence/RavenDbTests/Internal/Generated/WolverineHandlers/StringStartHandler2085759971.cs +++ b/src/Persistence/RavenDbTests/Internal/Generated/WolverineHandlers/StringStartHandler2085759971.cs @@ -18,16 +18,10 @@ public StringStartHandler2085759971(Raven.Client.Documents.IDocumentStore docume public override async System.Threading.Tasks.Task HandleAsync(Wolverine.Runtime.MessageContext context, System.Threading.CancellationToken cancellation) { + using var asyncDocumentSession = _documentStore.OpenAsyncSession(); // The actual message body var stringStart = (Wolverine.ComplianceTests.Sagas.StringStart)context.Envelope.Message; - - // Open a new document session - // message context to support the outbox functionality - using var asyncDocumentSession = _documentStore.OpenAsyncSession(); - context.EnlistInOutbox(new Wolverine.RavenDb.Internals.RavenDbEnvelopeTransaction(asyncDocumentSession, context)); - // Use optimistic concurrency for sagas - asyncDocumentSession.Advanced.UseOptimisticConcurrency = true; var stringBasicWorkflow = new Wolverine.ComplianceTests.Sagas.StringBasicWorkflow(); // The actual message execution diff --git a/src/Persistence/RavenDbTests/Internal/Generated/WolverineHandlers/WildcardStartHandler784149372.cs b/src/Persistence/RavenDbTests/Internal/Generated/WolverineHandlers/WildcardStartHandler784149372.cs index cb3f1dc9e..d5a563484 100644 --- a/src/Persistence/RavenDbTests/Internal/Generated/WolverineHandlers/WildcardStartHandler784149372.cs +++ b/src/Persistence/RavenDbTests/Internal/Generated/WolverineHandlers/WildcardStartHandler784149372.cs @@ -18,16 +18,10 @@ public WildcardStartHandler784149372(Raven.Client.Documents.IDocumentStore docum public override async System.Threading.Tasks.Task HandleAsync(Wolverine.Runtime.MessageContext context, System.Threading.CancellationToken cancellation) { + using var asyncDocumentSession = _documentStore.OpenAsyncSession(); // The actual message body var wildcardStart = (Wolverine.ComplianceTests.Sagas.WildcardStart)context.Envelope.Message; - - // Open a new document session - // message context to support the outbox functionality - using var asyncDocumentSession = _documentStore.OpenAsyncSession(); - context.EnlistInOutbox(new Wolverine.RavenDb.Internals.RavenDbEnvelopeTransaction(asyncDocumentSession, context)); - // Use optimistic concurrency for sagas - asyncDocumentSession.Advanced.UseOptimisticConcurrency = true; var stringBasicWorkflow = new Wolverine.ComplianceTests.Sagas.StringBasicWorkflow(); // The actual message execution diff --git a/src/Persistence/RavenDbTests/saga_storage_compliance.cs b/src/Persistence/RavenDbTests/saga_storage_compliance.cs index 5a0894fdb..1e9af297d 100644 --- a/src/Persistence/RavenDbTests/saga_storage_compliance.cs +++ b/src/Persistence/RavenDbTests/saga_storage_compliance.cs @@ -26,7 +26,7 @@ public IHost BuildHost() opts.CodeGeneration.GeneratedCodeOutputPath = AppContext.BaseDirectory.ParentDirectory().ParentDirectory().ParentDirectory().AppendPath("Internal", "Generated"); opts.CodeGeneration.TypeLoadMode = TypeLoadMode.Auto; - + // Shouldn't be necessary, but apparently is. Type scanning is not working // for some reason across the compliance tests opts.Discovery.IncludeType(); diff --git a/src/Persistence/RavenDbTests/using_storage_return_types_and_entity_attributes.cs b/src/Persistence/RavenDbTests/using_storage_return_types_and_entity_attributes.cs new file mode 100644 index 000000000..ff4967c9a --- /dev/null +++ b/src/Persistence/RavenDbTests/using_storage_return_types_and_entity_attributes.cs @@ -0,0 +1,46 @@ +using Microsoft.Extensions.DependencyInjection; +using Raven.Client.Documents; +using Wolverine; +using Wolverine.ComplianceTests; +using Wolverine.RavenDb; + +namespace RavenDbTests; + +[Collection("raven")] +public class using_storage_return_types_and_entity_attributes : StorageActionCompliance +{ + private readonly DatabaseFixture _fixture; + + public using_storage_return_types_and_entity_attributes(DatabaseFixture fixture) + { + _fixture = fixture; + } + + protected override void configureWolverine(WolverineOptions opts) + { + var store = _fixture.StartRavenStore(); + + // You *must* register the store after the RavenDb envelope storage + opts.UseRavenDbPersistence(); + opts.Services.AddSingleton(store); + opts.Policies.AutoApplyTransactions(); + opts.Durability.Mode = DurabilityMode.Solo; + + opts.CodeGeneration.ReferenceAssembly(typeof(Wolverine.RavenDb.IRavenDbOp).Assembly); + } + + public override async Task Load(string id) + { + var store = Host.Services.GetRequiredService(); + using var session = store.OpenAsyncSession(); + return await session.LoadAsync(id); + } + + public override async Task Persist(Todo todo) + { + var store = Host.Services.GetRequiredService(); + using var session = store.OpenAsyncSession(); + await session.StoreAsync(todo); + await session.SaveChangesAsync(); + } +} \ No newline at end of file diff --git a/src/Persistence/Wolverine.EntityFrameworkCore/Codegen/EFCorePersistenceFrameProvider.cs b/src/Persistence/Wolverine.EntityFrameworkCore/Codegen/EFCorePersistenceFrameProvider.cs index 55bed6c7f..7ca57bb9a 100644 --- a/src/Persistence/Wolverine.EntityFrameworkCore/Codegen/EFCorePersistenceFrameProvider.cs +++ b/src/Persistence/Wolverine.EntityFrameworkCore/Codegen/EFCorePersistenceFrameProvider.cs @@ -80,6 +80,29 @@ public Frame DetermineDeleteFrame(Variable sagaId, Variable saga, IServiceContai return new DbContextOperationFrame(dbContextType, saga, nameof(DbContext.Remove)); } + public Frame DetermineDeleteFrame(Variable variable, IServiceContainer container) + { + return DetermineDeleteFrame(null, variable, container); + } + + public Frame DetermineStorageActionFrame(Type entityType, Variable action, IServiceContainer container) + { + var dbContextType = DetermineDbContextType(entityType, container); + + var method = typeof(EfCoreStorageActionApplier).GetMethod("ApplyAction") + .MakeGenericMethod(entityType, dbContextType); + + var call = new MethodCall(typeof(EfCoreStorageActionApplier), method); + call.Arguments[1] = action; + + return call; + } + + public Frame DetermineStoreFrame(Variable variable, IServiceContainer container) + { + return DetermineUpdateFrame(variable, container); + } + public void ApplyTransactionSupport(IChain chain, IServiceContainer container) { if (chain.Tags.ContainsKey(UsingEfCoreTransaction)) return; @@ -109,6 +132,35 @@ public void ApplyTransactionSupport(IChain chain, IServiceContainer container) } } + public void ApplyTransactionSupport(IChain chain, IServiceContainer container, Type entityType) + { + if (chain.Tags.ContainsKey(UsingEfCoreTransaction)) return; + chain.Tags.Add(UsingEfCoreTransaction, true); + + var dbType = DetermineDbContextType(entityType, container); + + chain.Middleware.Insert(0, new EnrollDbContextInTransaction(dbType)); + + var saveChangesAsync = + dbType.GetMethod(nameof(DbContext.SaveChangesAsync), [typeof(CancellationToken)]); + + var call = new MethodCall(dbType, saveChangesAsync!) + { + CommentText = "Added by EF Core Transaction Middleware" + }; + + chain.Postprocessors.Add(call); + + chain.Postprocessors.Add(new CommitDbContextTransactionIfNecessary()); + + if (chain.RequiresOutbox() && chain.ShouldFlushOutgoingMessages()) + { +#pragma warning disable CS4014 + chain.Postprocessors.Add(new FlushOutgoingMessages()); +#pragma warning restore CS4014 + } + } + public bool CanApply(IChain chain, IServiceContainer container) { if (chain is SagaChain saga) @@ -172,7 +224,7 @@ public Type DetermineDbContextType(IChain chain, IServiceContainer container) { return DetermineDbContextType(saga.SagaType, container); } - +// START HERE. Look for any IStorageAction, and use the T var contextTypes = chain.ServiceDependencies(container, Type.EmptyTypes).Where(x => x.CanBeCastTo()).ToArray(); if (contextTypes.Length == 0) @@ -322,4 +374,29 @@ public override void GenerateCode(GeneratedMethod method, ISourceWriter writer) $"var {Saga.Usage} = await {_context!.Usage}.{nameof(DbContext.FindAsync)}<{Saga.VariableType.FullNameInCode()}>({_sagaId.Usage}).ConfigureAwait(false);"); Next?.GenerateCode(method, writer); } +} + +public static class EfCoreStorageActionApplier +{ + public static async Task ApplyAction(TDbContext context, IStorageAction action) where TDbContext : DbContext + { + if (action.Entity == null) return; + + switch (action.Action) + { + case StorageAction.Delete: + context.Remove(action.Entity); + break; + case StorageAction.Insert: + await context.AddAsync(action.Entity); + break; + case StorageAction.Store: + context.Update(action.Entity); // Not really correct, but let it go + break; + case StorageAction.Update: + context.Update(action.Entity); + break; + + } + } } \ No newline at end of file diff --git a/src/Persistence/Wolverine.Marten/Codegen/TransactionalFrame.cs b/src/Persistence/Wolverine.Marten/Codegen/CreateDocumentSessionFrame.cs similarity index 94% rename from src/Persistence/Wolverine.Marten/Codegen/TransactionalFrame.cs rename to src/Persistence/Wolverine.Marten/Codegen/CreateDocumentSessionFrame.cs index 0a342f407..f37ec1c42 100644 --- a/src/Persistence/Wolverine.Marten/Codegen/TransactionalFrame.cs +++ b/src/Persistence/Wolverine.Marten/Codegen/CreateDocumentSessionFrame.cs @@ -7,7 +7,7 @@ namespace Wolverine.Marten.Codegen; -internal class TransactionalFrame : Frame +internal class CreateDocumentSessionFrame : Frame { private readonly IChain _chain; private Variable? _cancellation; @@ -15,7 +15,7 @@ internal class TransactionalFrame : Frame private bool _createsSession; private Variable? _factory; - public TransactionalFrame(IChain chain) : base(true) + public CreateDocumentSessionFrame(IChain chain) : base(true) { _chain = chain; } diff --git a/src/Persistence/Wolverine.Marten/IMartenOp.cs b/src/Persistence/Wolverine.Marten/IMartenOp.cs index b13518ea8..85cd00355 100644 --- a/src/Persistence/Wolverine.Marten/IMartenOp.cs +++ b/src/Persistence/Wolverine.Marten/IMartenOp.cs @@ -1,6 +1,12 @@ -using JasperFx.Core; +using JasperFx.CodeGeneration; +using JasperFx.CodeGeneration.Frames; +using JasperFx.CodeGeneration.Model; +using JasperFx.Core; using Marten; -using MassTransit; +using Wolverine.Configuration; +using Wolverine.Marten.Persistence.Sagas; +using Wolverine.Runtime; +using Wolverine.Runtime.Handlers; namespace Wolverine.Marten; @@ -16,6 +22,51 @@ public interface IMartenOp : ISideEffect #endregion +internal class MartenOpPolicy : IChainPolicy +{ + public void Apply(IReadOnlyList chains, GenerationRules rules, IServiceContainer container) + { + foreach (var chain in chains) + { + var candidates = chain.ReturnVariablesOfType>().ToArray(); + if (candidates.Any()) + { + new MartenPersistenceFrameProvider().ApplyTransactionSupport(chain, container); + } + + foreach (var collection in candidates) + { + collection.UseReturnAction(v => new ForEachMartenOpFrame(v)); + } + } + } +} + +internal class ForEachMartenOpFrame : SyncFrame +{ + private readonly Variable _collection; + private Variable _session; + + public ForEachMartenOpFrame(Variable collection) + { + _collection = collection; + } + + public override IEnumerable FindVariables(IMethodVariables chain) + { + _session = chain.FindVariable(typeof(IDocumentSession)); + yield return _session; + yield return _collection; + } + + public override void GenerateCode(GeneratedMethod method, ISourceWriter writer) + { + writer.WriteComment("Apply each Marten op to the current document session"); + writer.Write($"foreach (var item_of_{_collection.Usage} in {_collection.Usage}) item_of_{_collection.Usage}.{nameof(IMartenOp.Execute)}({_session.Usage});"); + Next?.GenerateCode(method, writer); + } +} + /// /// Access to Marten related side effect return values from message handlers /// diff --git a/src/Persistence/Wolverine.Marten/MartenIntegration.cs b/src/Persistence/Wolverine.Marten/MartenIntegration.cs index f976c1625..2cb1076f5 100644 --- a/src/Persistence/Wolverine.Marten/MartenIntegration.cs +++ b/src/Persistence/Wolverine.Marten/MartenIntegration.cs @@ -58,6 +58,8 @@ public void Configure(WolverineOptions options) var transport = options.Transports.GetOrCreate(); transport.TransportSchemaName = TransportSchemaName; transport.MessageStorageSchemaName = MessageStorageSchemaName ?? "public"; + + options.Policies.Add(); } /// diff --git a/src/Persistence/Wolverine.Marten/Persistence/Sagas/MartenPersistenceFrameProvider.cs b/src/Persistence/Wolverine.Marten/Persistence/Sagas/MartenPersistenceFrameProvider.cs index f9fb65a27..951345093 100644 --- a/src/Persistence/Wolverine.Marten/Persistence/Sagas/MartenPersistenceFrameProvider.cs +++ b/src/Persistence/Wolverine.Marten/Persistence/Sagas/MartenPersistenceFrameProvider.cs @@ -1,4 +1,5 @@ -using JasperFx.CodeGeneration.Frames; +using System.Reflection; +using JasperFx.CodeGeneration.Frames; using JasperFx.CodeGeneration.Model; using JasperFx.Core.Reflection; using Marten; @@ -28,20 +29,29 @@ public Type DetermineSagaIdType(Type sagaType, IServiceContainer container) public void ApplyTransactionSupport(IChain chain, IServiceContainer container) { - if (!chain.Middleware.OfType().Any()) + if (!chain.Middleware.OfType().Any()) { - chain.Middleware.Add(new TransactionalFrame(chain)); - - if (chain is not SagaChain) + chain.Middleware.Add(new CreateDocumentSessionFrame(chain)); + } + + if (chain is not SagaChain) + { + if (!chain.Postprocessors.OfType().Any()) { - var saveChanges = MethodCall.For(x => x.SaveChangesAsync(default)); - saveChanges.CommentText = "Commit any outstanding Marten changes"; - chain.Postprocessors.Add(saveChanges); + chain.Postprocessors.Add(new DocumentSessionSaveChanges()); + } + if (!chain.Postprocessors.OfType().Any()) + { chain.Postprocessors.Add(new FlushOutgoingMessages()); } } } + + public void ApplyTransactionSupport(IChain chain, IServiceContainer container, Type entityType) + { + ApplyTransactionSupport(chain, container); + } public bool CanApply(IChain chain, IServiceContainer container) { @@ -69,9 +79,7 @@ public Frame DetermineInsertFrame(Variable saga, IServiceContainer container) public Frame CommitUnitOfWorkFrame(Variable saga, IServiceContainer container) { - var call = MethodCall.For(x => x.SaveChangesAsync(default)); - call.CommentText = "Commit all pending changes"; - return call; + return new DocumentSessionSaveChanges(); } public Frame DetermineUpdateFrame(Variable saga, IServiceContainer container) @@ -88,4 +96,59 @@ public Frame DetermineDeleteFrame(Variable sagaId, Variable saga, IServiceContai { return new DocumentSessionOperationFrame(saga, nameof(IDocumentSession.Delete)); } + + public Frame DetermineStoreFrame(Variable variable, IServiceContainer container) + { + return new DocumentSessionOperationFrame(variable, nameof(IDocumentSession.Store)); + } + + public Frame DetermineDeleteFrame(Variable variable, IServiceContainer container) + { + return new DocumentSessionOperationFrame(variable, nameof(IDocumentSession.Delete)); + } + + public Frame DetermineStorageActionFrame(Type entityType, Variable action, IServiceContainer container) + { + var method = typeof(MartenStorageActionApplier).GetMethod("ApplyAction") + .MakeGenericMethod(entityType); + + var call = new MethodCall(typeof(MartenStorageActionApplier), method); + call.Arguments[1] = action; + + return call; + } + +} + +public static class MartenStorageActionApplier +{ + public static void ApplyAction(IDocumentSession session, IStorageAction action) + { + if (action.Entity == null) return; + + switch (action.Action) + { + case StorageAction.Delete: + session.Delete(action.Entity!); + break; + case StorageAction.Insert: + session.Insert(action.Entity); + break; + case StorageAction.Store: + session.Store(action.Entity); + break; + case StorageAction.Update: + session.Update(action.Entity); + break; + + } + } +} + +internal class DocumentSessionSaveChanges : MethodCall +{ + public DocumentSessionSaveChanges() : base(typeof(IDocumentSession), ReflectionHelper.GetMethod(x => x.SaveChangesAsync(default))) + { + CommentText = "Save all pending changes to this Marten session"; + } } \ No newline at end of file diff --git a/src/Persistence/Wolverine.Postgresql/PostgresqlPersistenceFrameProvider.cs b/src/Persistence/Wolverine.Postgresql/PostgresqlPersistenceFrameProvider.cs index f4feb6830..b2799be57 100644 --- a/src/Persistence/Wolverine.Postgresql/PostgresqlPersistenceFrameProvider.cs +++ b/src/Persistence/Wolverine.Postgresql/PostgresqlPersistenceFrameProvider.cs @@ -31,6 +31,11 @@ public void ApplyTransactionSupport(IChain chain, IServiceContainer container) } } + public void ApplyTransactionSupport(IChain chain, IServiceContainer container, Type entityType) + { + ApplyTransactionSupport(chain, container); + } + public bool CanApply(IChain chain, IServiceContainer container) { if (chain is SagaChain) @@ -84,4 +89,19 @@ public Frame DetermineDeleteFrame(Variable sagaId, Variable saga, IServiceContai { return new SagaOperation(saga, SagaOperationType.DeleteAsync); } + + public Frame DetermineStoreFrame(Variable variable, IServiceContainer container) + { + throw new NotSupportedException("This provider only supports Insert() or Update()"); + } + + public Frame DetermineDeleteFrame(Variable variable, IServiceContainer container) + { + return new SagaOperation(variable, SagaOperationType.DeleteAsync); + } + + public Frame DetermineStorageActionFrame(Type entityType, Variable action, IServiceContainer container) + { + throw new NotSupportedException(); + } } \ No newline at end of file diff --git a/src/Persistence/Wolverine.RavenDb/Internals/BuildAsyncDocumentSession.cs b/src/Persistence/Wolverine.RavenDb/Internals/BuildAsyncDocumentSession.cs new file mode 100644 index 000000000..6229f83df --- /dev/null +++ b/src/Persistence/Wolverine.RavenDb/Internals/BuildAsyncDocumentSession.cs @@ -0,0 +1,27 @@ +using JasperFx.CodeGeneration.Model; +using JasperFx.Core.Reflection; +using Raven.Client.Documents; +using Raven.Client.Documents.Session; +using MethodCall = JasperFx.CodeGeneration.Frames.MethodCall; + +namespace Wolverine.RavenDb.Internals; + +internal class AsyncDocumentSessionSource : IVariableSource +{ + public bool Matches(Type type) + { + return type == typeof(IAsyncDocumentSession); + } + + public Variable Create(Type type) + { + return new BuildAsyncDocumentSession().Creates.Single(); + } +} + +internal class BuildAsyncDocumentSession : MethodCall +{ + public BuildAsyncDocumentSession() : base(typeof(IDocumentStore), ReflectionHelper.GetMethod(x => x.OpenAsyncSession())) + { + } +} \ No newline at end of file diff --git a/src/Persistence/Wolverine.RavenDb/Internals/RavenDbPersistenceFrameProvider.cs b/src/Persistence/Wolverine.RavenDb/Internals/RavenDbPersistenceFrameProvider.cs index ed39035cd..25088c35d 100644 --- a/src/Persistence/Wolverine.RavenDb/Internals/RavenDbPersistenceFrameProvider.cs +++ b/src/Persistence/Wolverine.RavenDb/Internals/RavenDbPersistenceFrameProvider.cs @@ -30,6 +30,11 @@ public void ApplyTransactionSupport(IChain chain, IServiceContainer container) } } + public void ApplyTransactionSupport(IChain chain, IServiceContainer container, Type entityType) + { + ApplyTransactionSupport(chain, container); + } + public bool CanApply(IChain chain, IServiceContainer container) { if (chain is SagaChain) @@ -86,8 +91,50 @@ public Frame DetermineDeleteFrame(Variable sagaId, Variable saga, IServiceContai { return new DeleteDocumentFrame(saga); } + + public Frame DetermineStoreFrame(Variable variable, IServiceContainer container) + { + return DetermineUpdateFrame(variable, container); + } + + public Frame DetermineDeleteFrame(Variable variable, IServiceContainer container) + { + return new DeleteDocumentFrame(variable); + } + + public Frame DetermineStorageActionFrame(Type entityType, Variable action, IServiceContainer container) + { + var method = typeof(RavenDbStorageActionApplier).GetMethod("ApplyAction") + .MakeGenericMethod(entityType); + + var call = new MethodCall(typeof(RavenDbStorageActionApplier), method); + call.Arguments[1] = action; + + return call; + } } +public static class RavenDbStorageActionApplier +{ + public static async Task ApplyAction(IAsyncDocumentSession session, IStorageAction action) + { + if (action.Entity == null) return; + + switch (action.Action) + { + case StorageAction.Delete: + session.Delete(action.Entity!); + break; + case StorageAction.Insert: + case StorageAction.Store: + case StorageAction.Update: + await session.StoreAsync(action.Entity); + break; + } + } +} + + internal class DeleteDocumentFrame : SyncFrame { private readonly Variable _saga; diff --git a/src/Persistence/Wolverine.RavenDb/WolverineRavenDbExtensions.cs b/src/Persistence/Wolverine.RavenDb/WolverineRavenDbExtensions.cs index d024e988d..da74e4b18 100644 --- a/src/Persistence/Wolverine.RavenDb/WolverineRavenDbExtensions.cs +++ b/src/Persistence/Wolverine.RavenDb/WolverineRavenDbExtensions.cs @@ -2,6 +2,7 @@ using Raven.Client.Documents; using Raven.Client.Documents.Operations; using Raven.Client.Documents.Queries; +using Wolverine.Attributes; using Wolverine.Persistence.Durability; using Wolverine.Persistence.Sagas; using Wolverine.RavenDb.Internals; @@ -20,7 +21,9 @@ public static WolverineOptions UseRavenDbPersistence(this WolverineOptions optio { options.Services.AddSingleton(); options.CodeGeneration.InsertFirstPersistenceStrategy(); + options.CodeGeneration.Sources.Add(new AsyncDocumentSessionSource()); options.Services.AddHostedService(); + options.CodeGeneration.ReferenceAssembly(typeof(WolverineRavenDbExtensions).Assembly); return options; } diff --git a/src/Persistence/Wolverine.SqlServer/SqlServerPersistenceFrameProvider.cs b/src/Persistence/Wolverine.SqlServer/SqlServerPersistenceFrameProvider.cs index b99739aa4..fd141f7a0 100644 --- a/src/Persistence/Wolverine.SqlServer/SqlServerPersistenceFrameProvider.cs +++ b/src/Persistence/Wolverine.SqlServer/SqlServerPersistenceFrameProvider.cs @@ -31,6 +31,11 @@ public void ApplyTransactionSupport(IChain chain, IServiceContainer container) } } + public void ApplyTransactionSupport(IChain chain, IServiceContainer container, Type entityType) + { + ApplyTransactionSupport(chain, container); + } + public bool CanApply(IChain chain, IServiceContainer container) { if (chain is SagaChain) @@ -83,4 +88,19 @@ public Frame DetermineDeleteFrame(Variable sagaId, Variable saga, IServiceContai { return new SagaOperation(saga, SagaOperationType.DeleteAsync); } + + public Frame DetermineStoreFrame(Variable variable, IServiceContainer container) + { + throw new NotSupportedException("This provider only supports Insert() or Update()"); + } + + public Frame DetermineDeleteFrame(Variable variable, IServiceContainer container) + { + return new SagaOperation(variable, SagaOperationType.DeleteAsync); + } + + public Frame DetermineStorageActionFrame(Type entityType, Variable action, IServiceContainer container) + { + throw new NotSupportedException(); + } } \ No newline at end of file diff --git a/src/Samples/EFCoreSample/ItemService.Tests/ItemService.Tests.csproj b/src/Samples/EFCoreSample/ItemService.Tests/ItemService.Tests.csproj index d9b13ceb7..b39ae1658 100644 --- a/src/Samples/EFCoreSample/ItemService.Tests/ItemService.Tests.csproj +++ b/src/Samples/EFCoreSample/ItemService.Tests/ItemService.Tests.csproj @@ -1,6 +1,6 @@ - net8.0;net9.0 + net9.0 @@ -9,6 +9,7 @@ + diff --git a/src/Samples/EFCoreSample/ItemService.Tests/end_to_end.cs b/src/Samples/EFCoreSample/ItemService.Tests/end_to_end.cs index bfb38e171..fcf2be810 100644 --- a/src/Samples/EFCoreSample/ItemService.Tests/end_to_end.cs +++ b/src/Samples/EFCoreSample/ItemService.Tests/end_to_end.cs @@ -80,4 +80,20 @@ await host.Scenario(x => var item = await context.Items.FirstOrDefaultAsync(x => x.Name == name); item.ShouldNotBeNull(); } + + [Fact] + public async Task fetch_through_entity_attribute() + { + var name = Guid.NewGuid().ToString(); + using var host = await AlbaHost.For(); + using var nested = host.Services.CreateScope(); + var context = nested.ServiceProvider.GetRequiredService(); + + var id = Guid.NewGuid(); + context.Add(new Item { Id = id, Name = name }); + await context.SaveChangesAsync(); + + var response = await host.GetAsJson("/api/item/" + id); + response.Name.ShouldBe(name); + } } \ No newline at end of file diff --git a/src/Samples/EFCoreSample/ItemService/CreateItemController.cs b/src/Samples/EFCoreSample/ItemService/CreateItemController.cs index 6379ba938..78492fe6c 100644 --- a/src/Samples/EFCoreSample/ItemService/CreateItemController.cs +++ b/src/Samples/EFCoreSample/ItemService/CreateItemController.cs @@ -1,7 +1,9 @@ +using JasperFx.Core; using Microsoft.AspNetCore.Mvc; using Wolverine.Attributes; using Wolverine.EntityFrameworkCore; using Wolverine.Http; +using Wolverine.Persistence; namespace ItemService; @@ -82,21 +84,18 @@ public static class CreateItemEndpoint { [Transactional] [WolverinePost("/items/create4"), EmptyResponse] - public static ItemCreated Post(CreateItemCommand command, ItemsDbContext dbContext) + public static (ItemCreated, Insert) Post(CreateItemCommand command) { // Create a new Item entity var item = new Item { - Name = command.Name + Name = command.Name, + Id = CombGuidIdGeneration.NewGuid() }; - // Add the item to the current - // DbContext unit of work - dbContext.Items.Add(item); - - return new ItemCreated - { - Id = item.Id - }; + return (new ItemCreated { Id = item.Id }, Storage.Insert(item)); } + + [WolverineGet("/api/item/{id}")] + public static Item Get([Entity] Item item) => item; } \ No newline at end of file diff --git a/src/Samples/EFCoreSample/ItemService/ItemService.csproj b/src/Samples/EFCoreSample/ItemService/ItemService.csproj index 32f7beda4..bba5a0e88 100644 --- a/src/Samples/EFCoreSample/ItemService/ItemService.csproj +++ b/src/Samples/EFCoreSample/ItemService/ItemService.csproj @@ -1,6 +1,6 @@ - net8.0;net9.0 + net9.0 @@ -13,15 +13,7 @@ - - - - - - - - - + diff --git a/src/Testing/CoreTests/Persistence/StorageSamples.cs b/src/Testing/CoreTests/Persistence/StorageSamples.cs new file mode 100644 index 000000000..55a0e1a68 --- /dev/null +++ b/src/Testing/CoreTests/Persistence/StorageSamples.cs @@ -0,0 +1,48 @@ +using Wolverine.Persistence; + +namespace CoreTests.Persistence; + +public class StorageSamples +{ + +} + +public class Item +{ + public Guid Id { get; set; } + public string Name { get; set; } +} + +public interface IProfanityDetector +{ + bool HasProfanity(string text); +} + +#region sample_using_conditional_storage_action + +public record CreateItem(Guid Id, string Name); + +public static class CreateItemHandler +{ + // It's always a struggle coming up with sample use cases + public static IStorageAction Handle( + CreateItem command, + IProfanityDetector detector) + { + // First see if the name is valid + if (detector.HasProfanity(command.Name)) + { + // and if not, do nothing + return Storage.Nothing(); + } + + return Storage.Insert(new Item + { + Id = command.Id, + Name = command.Name + }); + } +} + +#endregion + diff --git a/src/Testing/CoreTests/Persistence/using_storage_return_types_and_entity_attributes.cs b/src/Testing/CoreTests/Persistence/using_storage_return_types_and_entity_attributes.cs new file mode 100644 index 000000000..b30621b63 --- /dev/null +++ b/src/Testing/CoreTests/Persistence/using_storage_return_types_and_entity_attributes.cs @@ -0,0 +1,95 @@ +using Microsoft.Extensions.DependencyInjection; +using Wolverine.ComplianceTests; +using Wolverine.Persistence; +using Wolverine.Persistence.Sagas; +using Wolverine.Tracking; +using Xunit; + +namespace CoreTests.Persistence; + +public class using_storage_return_types_and_entity_attributes : StorageActionCompliance +{ + protected override void configureWolverine(WolverineOptions opts) + { + // Nothing, just use the in memory persistor + } + + public override Task Load(string id) + { + return Task.FromResult(Host.Services.GetRequiredService().Load(id)); + } + + public override Task Persist(Todo todo) + { + Host.Services.GetRequiredService().Store(todo); + return Task.CompletedTask; + } +} + +public class using_multiple_storage_actions : IntegrationContext +{ + public using_multiple_storage_actions(DefaultApp @default) : base(@default) + { + } + + [Fact] + public async Task use_multiple_storage_actions_of_different_types() + { + var command = new CreateTeamAndPlayer(Guid.NewGuid(), "Chiefs", "Patrick Mahomes"); + await Host.InvokeMessageAndWaitAsync(command); + + var persistor = Host.Services.GetRequiredService(); + persistor.Load(command.Id).Name.ShouldBe(command.TeamName); + persistor.Load(command.Id).Name.ShouldBe(command.PlayerName); + } + + [Fact] + public async Task use_tuple_of_multiple_actions_of_same_entity() + { + var command = new CreateMultiplePositions("Shortstop", "Pitcher"); + await Host.InvokeMessageAndWaitAsync(command); + + var persistor = Host.Services.GetRequiredService(); + persistor.Load("Shortstop").ShouldNotBeNull(); + persistor.Load("Pitcher").ShouldNotBeNull(); + } +} + +public class Team +{ + public Guid Id { get; set; } + public string Name { get; set; } +} + +public class Player +{ + public Guid Id { get; set; } + public string Name { get; set; } +} + +public record CreateTeamAndPlayer(Guid Id, string TeamName, string PlayerName); + +public record CreateMultiplePositions(string First, string Second); + +public class Position +{ + public string Id { get; set; } +} + +public static class CreateMultiplePositionsHandler +{ + public static (IStorageAction, IStorageAction) Handle(CreateMultiplePositions command) + { + return (Storage.Insert(new Position { Id = command.First }), + Storage.Insert(new Position { Id = command.Second })); + } +} + +public static class CreateTeamAndPlayerHandler +{ + public static (IStorageAction, IStorageAction) Handle(CreateTeamAndPlayer command) + { + return (Storage.Insert(new Team { Id = command.Id, Name = command.TeamName }), + Storage.Insert(new Player { Id = command.Id, Name = command.PlayerName })); + } +} \ No newline at end of file diff --git a/src/Testing/CoreTests/Runtime/Handlers/HandlerChain_TryFindVariable.cs b/src/Testing/CoreTests/Runtime/Handlers/HandlerChain_TryFindVariable.cs new file mode 100644 index 000000000..b2d734fd2 --- /dev/null +++ b/src/Testing/CoreTests/Runtime/Handlers/HandlerChain_TryFindVariable.cs @@ -0,0 +1,71 @@ +using Wolverine.Attributes; +using Wolverine.Codegen; +using Wolverine.Runtime.Handlers; +using Xunit; + +namespace CoreTests.Runtime.Handlers; + +public class HandlerChain_TryFindVariable +{ + [Fact] + public void for_matching_member_name_on_name_and_type() + { + var chain = HandlerChain.For(x => x.Handle(null), new HandlerGraph()); + + chain.TryFindVariable(nameof(CreateThing.Id), ValueSource.InputMember, typeof(Guid), out var variable) + .ShouldBeTrue(); + + variable.ShouldBeOfType() + .Member.Name.ShouldBe("Id"); + } + + [Fact] + public void miss_on_type() + { + var chain = HandlerChain.For(x => x.Handle(null), new HandlerGraph()); + + chain.TryFindVariable(nameof(CreateThing.Id), ValueSource.InputMember, typeof(int), out var variable) + .ShouldBeFalse(); + } + + [Fact] + public void miss_on_member_name() + { + var chain = HandlerChain.For(x => x.Handle(null), new HandlerGraph()); + + chain.TryFindVariable("wrong", ValueSource.InputMember, typeof(Guid), out var variable) + .ShouldBeFalse(); + } + + [Fact] + public void for_matching_member_name_on_name_and_type_and_anything_is_the_source() + { + var chain = HandlerChain.For(x => x.Handle(null), new HandlerGraph()); + + chain.TryFindVariable(nameof(CreateThing.Id), ValueSource.Anything, typeof(Guid), out var variable) + .ShouldBeTrue(); + + variable.ShouldBeOfType() + .Member.Name.ShouldBe("Id"); + } + + [Fact] + public void miss_on_unsupported_value_sources() + { + var chain = HandlerChain.For(x => x.Handle(null), new HandlerGraph()); + + chain.TryFindVariable(nameof(CreateThing.Id), ValueSource.RouteValue, typeof(Guid), out var variable) + .ShouldBeFalse(); + } + +} + +public record CreateThing(Guid Id, string Name, string Color); + +public class CreateThingHandler +{ + public void Handle(CreateThing command) + { + // Nothing + } +} diff --git a/src/Testing/Wolverine.ComplianceTests/StorageActionCompliance.cs b/src/Testing/Wolverine.ComplianceTests/StorageActionCompliance.cs new file mode 100644 index 000000000..4575430d1 --- /dev/null +++ b/src/Testing/Wolverine.ComplianceTests/StorageActionCompliance.cs @@ -0,0 +1,446 @@ +using Microsoft.Extensions.Hosting; +using Shouldly; +using Wolverine.Persistence; +using Wolverine.Tracking; +using Xunit; + +namespace Wolverine.ComplianceTests; + +public abstract class StorageActionCompliance : IAsyncLifetime +{ + public List Disposables = new(); + + public async Task InitializeAsync() + { + Host = await Microsoft.Extensions.Hosting.Host.CreateDefaultBuilder() + .UseWolverine(opts => + { + opts.Discovery.DisableConventionalDiscovery() + .IncludeType(typeof(TodoHandler)) + .IncludeType(typeof(MarkTaskCompleteIfBrokenHandler)) + .IncludeType(typeof(ExamineFirstHandler)) + .IncludeType(typeof(StoreManyHandler)); + + configureWolverine(opts); + }).StartAsync(); + + await initialize(); + } + + protected virtual Task initialize() + { + return Task.CompletedTask; + } + + protected abstract void configureWolverine(WolverineOptions opts); + + public async Task DisposeAsync() + { + foreach (var disposable in Disposables) + { + disposable.Dispose(); + } + + await Host.StopAsync(); + } + + + public IHost Host { get; set; } + + // These two methods will be changed + public abstract Task Load(string id); + + public abstract Task Persist(Todo todo); + + [Fact] + public async Task use_insert_as_return_value() + { + var command = new CreateTodo(Guid.NewGuid().ToString(), "Write docs"); + var tracked = await Host.InvokeMessageAndWaitAsync(command); + + // Should NOT be trying to send the entity as a cascading message + tracked.NoRoutes.Envelopes().Any().ShouldBeFalse(); + + var todo = await Load(command.Id); + + todo.Name.ShouldBe("Write docs"); + } + + [Fact] + public async Task use_entity_attribute_with_id() + { + var command = new CreateTodo(Guid.NewGuid().ToString(), "Write docs"); + await Host.InvokeMessageAndWaitAsync(command); + + await Host.InvokeMessageAndWaitAsync(new RenameTodo(command.Id, "New name")); + + var todo = await Load(command.Id); + todo.Name.ShouldBe("New name"); + } + + [Fact] + public async Task use_entity_attribute_with_entity_id() + { + var command = new CreateTodo(Guid.NewGuid().ToString(), "Write docs"); + await Host.InvokeMessageAndWaitAsync(command); + + await Host.InvokeMessageAndWaitAsync(new RenameTodo2(command.Id, "New name2")); + + var todo = await Load(command.Id); + todo.Name.ShouldBe("New name2"); + } + + [Fact] + public async Task use_entity_attribute_with_explicit_id() + { + var command = new CreateTodo(Guid.NewGuid().ToString(), "Write docs"); + await Host.InvokeMessageAndWaitAsync(command); + + await Host.InvokeMessageAndWaitAsync(new RenameTodo3(command.Id, "New name3")); + + var todo = await Load(command.Id); + todo.Name.ShouldBe("New name3"); + } + + + [Fact] + public async Task use_delete_as_return_value() + { + var command = new CreateTodo(Guid.NewGuid().ToString(), "Write docs"); + var tracked = await Host.InvokeMessageAndWaitAsync(command); + + // Should NOT be trying to send the entity as a cascading message + tracked.NoRoutes.Envelopes().Any().ShouldBeFalse(); + + var tracked2 = await Host.InvokeMessageAndWaitAsync(new DeleteTodo(command.Id)); + tracked2.NoRoutes.Envelopes().Any().ShouldBeFalse(); + + var todo = await Load(command.Id); + + todo.ShouldBeNull(); + } + + [Fact] + public async Task use_generic_action_as_insert() + { + var shouldInsert = new MaybeInsertTodo(Guid.NewGuid().ToString(), "Pick up milk", true); + var shouldDoNothing = new MaybeInsertTodo(Guid.NewGuid().ToString(), "Start soup", false); + + await Host.InvokeMessageAndWaitAsync(shouldInsert); + await Host.InvokeMessageAndWaitAsync(shouldDoNothing); + + (await Load(shouldInsert.Id)).Name.ShouldBe("Pick up milk"); + (await Load(shouldDoNothing.Id)).ShouldBeNull(); + } + + [Fact] + public async Task use_generic_action_as_delete() + { + var command = new CreateTodo(Guid.NewGuid().ToString(), "Write docs"); + await Host.InvokeMessageAndWaitAsync(command); + + await Host.InvokeMessageAndWaitAsync(new AlterTodo(command.Id, "New text", StorageAction.Delete)); + + (await Load(command.Id)).ShouldBeNull(); + } + + [Fact] + public async Task use_generic_action_as_update() + { + var command = new CreateTodo(Guid.NewGuid().ToString(), "Write docs"); + await Host.InvokeMessageAndWaitAsync(command); + + await Host.InvokeMessageAndWaitAsync(new AlterTodo(command.Id, "New text", StorageAction.Update)); + + (await Load(command.Id)).Name.ShouldBe("New text"); + } + + [Fact] + public async Task use_generic_action_as_store() + { + var command = new CreateTodo(Guid.NewGuid().ToString(), "Write docs"); + await Host.InvokeMessageAndWaitAsync(command); + + await Host.InvokeMessageAndWaitAsync(new AlterTodo(command.Id, "New text", StorageAction.Store)); + + (await Load(command.Id)).Name.ShouldBe("New text"); + } + + [Fact] + public async Task do_nothing_as_generic_action() + { + var command = new CreateTodo(Guid.NewGuid().ToString(), "Write docs"); + await Host.InvokeMessageAndWaitAsync(command); + + await Host.InvokeMessageAndWaitAsync(new AlterTodo(command.Id, "New text", StorageAction.Nothing)); + + (await Load(command.Id)).Name.ShouldBe("Write docs"); + } + + [Fact] + public async Task do_nothing_if_storage_action_is_null() + { + // Just a smoke test + var command = new ReturnNullInsert(); + await Host.InvokeMessageAndWaitAsync(command); + } + + [Fact] + public async Task do_nothing_if_generic_storage_action_is_null() + { + // Just a smoke test + var command = new ReturnNullStorageAction(); + await Host.InvokeMessageAndWaitAsync(command); + } + + [Fact] + public async Task do_not_execute_the_handler_if_the_entity_is_not_found() + { + // This handler would blow up if the Todo is null + await Host.InvokeMessageAndWaitAsync(new CompleteTodo(Guid.NewGuid().ToString())); + + var todoId = Guid.NewGuid().ToString(); + await Host.InvokeMessageAndWaitAsync(new CreateTodo(todoId, "Write docs")); + + // This should be fine + await Host.InvokeMessageAndWaitAsync(new CompleteTodo(todoId)); + + (await Load(todoId)).IsComplete.ShouldBeTrue(); + } + + [Fact] + public async Task handler_not_required_entity_attributes() + { + // This handler will do nothing if the Todo is null + await Host.InvokeMessageAndWaitAsync(new MaybeCompleteTodo(Guid.NewGuid().ToString())); + + var todoId = Guid.NewGuid().ToString(); + await Host.InvokeMessageAndWaitAsync(new CreateTodo(todoId, "Write docs")); + + // This should be fine + await Host.InvokeMessageAndWaitAsync(new MaybeCompleteTodo(todoId)); + + (await Load(todoId)).IsComplete.ShouldBeTrue(); + } + + [Fact] + public async Task entity_can_be_used_in_before_methods_implied_from_main_handler_method() + { + var todoId = Guid.NewGuid().ToString(); + await Host.InvokeMessageAndWaitAsync(new CreateTodo(todoId, "Write docs")); + + // This should be fine + await Host.InvokeMessageAndWaitAsync(new MarkTaskCompleteWithBeforeUsage(todoId)); + + (await Load(todoId)).IsComplete.ShouldBeTrue(); + } + + [Fact] + public async Task can_use_attribute_on_before_methods() + { + ExamineFirstHandler.DidContinue = false; + + // Negative case, Todo does not exist, main handler should NOT have executed + await Host.InvokeMessageAndWaitAsync(new ExamineFirst(Guid.NewGuid().ToString())); + ExamineFirstHandler.DidContinue.ShouldBeFalse(); + + // Positive case, Todo exists + var todoId = Guid.NewGuid().ToString(); + await Host.InvokeMessageAndWaitAsync(new CreateTodo(todoId, "Write docs")); + await Host.InvokeMessageAndWaitAsync(new ExamineFirst(todoId)); + + ExamineFirstHandler.DidContinue.ShouldBeTrue(); + + + } + + [Fact] + public async Task use_unit_of_work_as_return_value() + { + var storeMany = new StoreMany([Guid.NewGuid().ToString(), Guid.NewGuid().ToString(), Guid.NewGuid().ToString()]); + await Host.InvokeMessageAndWaitAsync(storeMany); + + (await Load(storeMany.Adds[0])).ShouldNotBeNull(); + (await Load(storeMany.Adds[1])).ShouldNotBeNull(); + (await Load(storeMany.Adds[2])).ShouldNotBeNull(); + + } +} + + +public class Todo +{ + public string Id { get; set; } + public string? Name { get; set; } + public bool IsComplete { get; set; } +} + +public record CreateTodo(string Id, string Name); +public record CreateTodo2(string Id, string Name); + +public record DeleteTodo(string Id); + +public record RenameTodo(string Id, string Name); +public record RenameTodo2(string TodoId, string Name); +public record RenameTodo3(string Identity, string Name); + +public record AlterTodo(string Id, string Name, StorageAction Action); + +public record MaybeInsertTodo(string Id, string Name, bool ShouldInsert); + +public record ReturnNullInsert; +public record ReturnNullStorageAction; + +public static class TodoHandler +{ + public static Insert Handle(CreateTodo command) => Storage.Insert(new Todo + { + Id = command.Id, + Name = command.Name + }); + + public static Store Handle(CreateTodo2 command) => Storage.Store(new Todo + { + Id = command.Id, + Name = command.Name + }); + + // Use "Id" as the default member + public static Update Handle( + // The first argument is always the incoming message + RenameTodo command, + + // By using this attribute, we're telling Wolverine + // to load the Todo entity from the configured + // persistence of the app using a member on the + // incoming message type + [Entity] Todo todo) + { + // Do your actual business logic + todo.Name = command.Name; + + // Tell Wolverine that you want this entity + // updated in persistence + return Storage.Update(todo); + } + + // Use "TodoId" as the default member + public static Update Handle(RenameTodo2 command, [Entity] Todo todo) + { + todo.Name = command.Name; + return Storage.Update(todo); + } + + // Use the explicit member + public static Update Handle(RenameTodo3 command, [Entity("Identity")] Todo todo) + { + todo.Name = command.Name; + return Storage.Update(todo); + } + + public static Delete Handle(DeleteTodo command, [Entity("Identity")] Todo todo) + { + return Storage.Delete(todo); + } + + public static IStorageAction Handle(AlterTodo command, [Entity("Identity")] Todo todo) + { + switch (command.Action) + { + case StorageAction.Delete: + return Storage.Delete(todo); + case StorageAction.Update: + todo.Name = command.Name; + return Storage.Update(todo); + case StorageAction.Store: + todo.Name = command.Name; + return Storage.Store(todo); + default: + return Storage.Nothing(); + } + } + + public static IStorageAction Handle(MaybeInsertTodo command) + { + if (command.ShouldInsert) + { + return Storage.Insert(new Todo { Id = command.Id, Name = command.Name }); + } + + return Storage.Nothing(); + } + + public static Insert? Handle(ReturnNullInsert command) => null; + + public static IStorageAction? Handle(ReturnNullStorageAction command) => null; + + public static IStorageAction Handle(CompleteTodo command, [Entity] Todo todo) + { + if (todo == null) throw new ArgumentNullException(nameof(todo)); + todo.IsComplete = true; + return Storage.Update(todo); + } + + public static IStorageAction Handle(MaybeCompleteTodo command, [Entity(Required = false)] Todo? todo) + { + if (todo == null) return Storage.Nothing(); + todo.IsComplete = true; + return Storage.Update(todo); + } +} + +public record CompleteTodo(string Id); +public record MaybeCompleteTodo(string Id); + +public record MarkTaskCompleteWithBeforeUsage(string Id); + +public static class MarkTaskCompleteIfBrokenHandler +{ + // Just proving out that you can get at the entity + // in a Before method + public static void Before(Todo todo) + { + todo.ShouldNotBeNull(); + } + + public static Update Handle(MarkTaskCompleteWithBeforeUsage command, [Entity] Todo todo) + { + todo.IsComplete = true; + return Storage.Update(todo); + } +} + +public record ExamineFirst(string TodoId); + +public static class ExamineFirstHandler +{ + public static bool DidContinue { get; set; } + + public static HandlerContinuation Before([Entity] Todo todo) + { + return todo.IsComplete ? HandlerContinuation.Stop : HandlerContinuation.Continue; + } + + public static void Handle(ExamineFirst command) => DidContinue = true; +} + +#region sample_using_unit_of_work_as_side_effect + +public record StoreMany(string[] Adds); + +public static class StoreManyHandler +{ + public static UnitOfWork Handle(StoreMany command) + { + var uow = new UnitOfWork(); + foreach (var add in command.Adds) + { + uow.Insert(new Todo { Id = add }); + } + + return uow; + } +} + +#endregion + diff --git a/src/Wolverine/Attributes/ModifyChainAttribute.cs b/src/Wolverine/Attributes/ModifyChainAttribute.cs index ae2d00bb8..0a642f6e5 100644 --- a/src/Wolverine/Attributes/ModifyChainAttribute.cs +++ b/src/Wolverine/Attributes/ModifyChainAttribute.cs @@ -12,4 +12,26 @@ namespace Wolverine.Attributes; public abstract class ModifyChainAttribute : Attribute { public abstract void Modify(IChain chain, GenerationRules rules, IServiceContainer container); -} \ No newline at end of file +} + +#region sample_ValueSource + +public enum ValueSource +{ + /// + /// This value can be sourced by any mechanism that matches the name. This is the default. + /// + Anything, + + /// + /// The value should be sourced by a property or field on the message type or HTTP request type + /// + InputMember, + + /// + /// The value should be sourced by a route argument of an HTTP request + /// + RouteValue +} + +#endregion \ No newline at end of file diff --git a/src/Wolverine/Attributes/WolverineParameterAttribute.cs b/src/Wolverine/Attributes/WolverineParameterAttribute.cs new file mode 100644 index 000000000..b7818fc49 --- /dev/null +++ b/src/Wolverine/Attributes/WolverineParameterAttribute.cs @@ -0,0 +1,58 @@ +using System.Reflection; +using JasperFx.CodeGeneration; +using JasperFx.CodeGeneration.Frames; +using JasperFx.CodeGeneration.Model; +using JasperFx.Core.Reflection; +using Wolverine.Configuration; +using Wolverine.Runtime; + +namespace Wolverine.Attributes; + +/// +/// Base class for any attributes on parameters to Wolverine message handler or HTTP endpoint +/// methods that modifies the codegen for that handler +/// +[AttributeUsage(AttributeTargets.Parameter, Inherited = true, AllowMultiple = false)] +public abstract class WolverineParameterAttribute : Attribute +{ + protected WolverineParameterAttribute() + { + } + + protected WolverineParameterAttribute(string argumentName) + { + ArgumentName = argumentName; + } + + public string ArgumentName { get; set; } + + /// + /// Where should the identity value for resolving this parameter come from? + /// Default is a named member on the message type or HTTP request type (if one exists) + /// + public ValueSource ValueSource { get; set; } = ValueSource.InputMember; + + /// + /// Called by Wolverine during bootstrapping to modify the code generation + /// for an HTTP endpoint with the decorated parameter + /// + /// + /// + /// + /// + public abstract Variable Modify(IChain chain, ParameterInfo parameter, + IServiceContainer container, GenerationRules rules); + + internal static void TryApply(MethodCall call, IServiceContainer container, GenerationRules rules, IChain chain) + { + var parameters = call.Method.GetParameters(); + for (int i = 0; i < parameters.Length; i++) + { + if (parameters[i].TryGetAttribute(out var att)) + { + var variable = att.Modify(chain, parameters[i], container, rules); + call.Arguments[i] = variable; + } + } + } +} \ No newline at end of file diff --git a/src/Wolverine/Codegen/MessageMemberVariable.cs b/src/Wolverine/Codegen/MessageMemberVariable.cs index 93f7f8314..753370ef4 100644 --- a/src/Wolverine/Codegen/MessageMemberVariable.cs +++ b/src/Wolverine/Codegen/MessageMemberVariable.cs @@ -9,7 +9,10 @@ namespace Wolverine.Codegen; /// public class MessageMemberVariable : Variable { + public MemberInfo Member { get; } + public MessageMemberVariable(MemberInfo member, Type messageType) : base(member.GetRawMemberType(), $"(({messageType.FullNameInCode()})context.Envelope.Message).{member.Name}") { + Member = member; } } \ No newline at end of file diff --git a/src/Wolverine/Configuration/Chain.cs b/src/Wolverine/Configuration/Chain.cs index 92aae0fc6..2b9201fa7 100644 --- a/src/Wolverine/Configuration/Chain.cs +++ b/src/Wolverine/Configuration/Chain.cs @@ -155,6 +155,9 @@ public IEnumerable ReturnVariablesOfType(Type interfaceType) return HandlerCalls().SelectMany(x => x.Creates).Where(x => x.VariableType.CanBeCastTo(interfaceType)); } + public abstract bool TryFindVariable(string valueName, ValueSource source, Type valueType, out Variable variable); + public abstract Frame[] AddStopConditionIfNull(Variable variable); + private static Type[] _typesToIgnore = new Type[] { typeof(DateOnly), diff --git a/src/Wolverine/Configuration/IChain.cs b/src/Wolverine/Configuration/IChain.cs index 5304c181a..e5217a307 100644 --- a/src/Wolverine/Configuration/IChain.cs +++ b/src/Wolverine/Configuration/IChain.cs @@ -3,6 +3,7 @@ using JasperFx.CodeGeneration.Frames; using JasperFx.CodeGeneration.Model; using JasperFx.Core.Reflection; +using Wolverine.Attributes; using Wolverine.Logging; using Wolverine.Runtime; @@ -113,6 +114,23 @@ public interface IChain /// /// IEnumerable ReturnVariablesOfType(Type interfaceType); + + /// + /// Used by code generation to find a simple value on input types, headers, route values, + /// query string, or claims for use in loading other data + /// + /// + /// + /// + /// + /// + bool TryFindVariable(string valueName, ValueSource source, Type valueType, out Variable variable); + + /// + /// Used by code generation to add a middleware Frame that aborts the processing if the variable is null + /// + /// + Frame[] AddStopConditionIfNull(Variable variable); } #endregion \ No newline at end of file diff --git a/src/Wolverine/ISideEffect.cs b/src/Wolverine/ISideEffect.cs index 171027a3e..d4255cddb 100644 --- a/src/Wolverine/ISideEffect.cs +++ b/src/Wolverine/ISideEffect.cs @@ -1,9 +1,12 @@ using System.Reflection; using JasperFx.CodeGeneration; using JasperFx.CodeGeneration.Frames; +using JasperFx.CodeGeneration.Model; using JasperFx.Core; using JasperFx.Core.Reflection; using Wolverine.Configuration; +using Wolverine.Persistence; +using Wolverine.Persistence.Sagas; using Wolverine.Runtime; using Wolverine.Runtime.Handlers; @@ -16,6 +19,17 @@ namespace Wolverine; /// public interface ISideEffect : IWolverineReturnType; + +/// +/// Static interface that marks a return type that "knows" how to do extra +/// code generation to handle a side effect +/// +public interface ISideEffectAware : ISideEffect +{ + static abstract Frame BuildFrame(IChain chain, Variable variable, GenerationRules rules, + IServiceContainer container); +} + internal class SideEffectPolicy : IChainPolicy { public const string SyncMethod = "Execute"; @@ -25,30 +39,68 @@ public void Apply(IReadOnlyList chains, GenerationRules rules, IServiceC { foreach (var chain in chains) { - var sideEffects = chain.ReturnVariablesOfType(); - foreach (var effect in sideEffects) + lookForSingularSideEffects(rules, container, chain); + } + } + + private static void lookForSingularSideEffects(GenerationRules rules, IServiceContainer container, IChain chain) + { + var sideEffects = chain.ReturnVariablesOfType(); + foreach (var effect in sideEffects.ToArray()) + { + if (effect.VariableType.CanBeCastTo(typeof(ISideEffectAware))) { - var method = findMethod(effect.VariableType); - if (method == null) + if (!Storage.TryApply(effect, rules, container, chain)) { - throw new InvalidSideEffectException( - $"Invalid Wolverine side effect exception for {effect.VariableType.FullNameInCode()}, no public {SyncMethod}/{AsyncMethod} method found"); + var applier = typeof(Applier<>).CloseAndBuildAs(effect.VariableType); + var frame = applier.Apply(chain, effect, rules, container); + effect.UseReturnAction(v => frame); } + } + else + { + applySideEffectExecution(effect, chain); + } + + } + } - foreach (var parameter in method.GetParameters()) chain.AddDependencyType(parameter.ParameterType); + internal interface IApplier + { + Frame Apply(IChain chain, Variable variable, GenerationRules rules, + IServiceContainer container); + } - effect.UseReturnAction(_ => - { - return new IfElseNullGuardFrame.IfNullGuardFrame( - effect, - new MethodCall(effect.VariableType, method) - { - Target = effect, - CommentText = $"Placed by Wolverine's {nameof(ISideEffect)} policy" - }); - }, "Side Effect Policy"); - } + internal class Applier : IApplier where T : ISideEffectAware + { + public Frame Apply(IChain chain, Variable variable, GenerationRules rules, + IServiceContainer container) + { + return T.BuildFrame(chain, variable, rules, container); + } + } + + private static void applySideEffectExecution(Variable effect, IChain chain) + { + var method = findMethod(effect.VariableType); + if (method == null) + { + throw new InvalidSideEffectException( + $"Invalid Wolverine side effect exception for {effect.VariableType.FullNameInCode()}, no public {SyncMethod}/{AsyncMethod} method found"); } + + foreach (var parameter in method.GetParameters()) chain.AddDependencyType(parameter.ParameterType); + + effect.UseReturnAction(_ => + { + return new IfElseNullGuardFrame.IfNullGuardFrame( + effect, + new MethodCall(effect.VariableType, method) + { + Target = effect, + CommentText = $"Placed by Wolverine's {nameof(ISideEffect)} policy" + }); + }, "Side Effect Policy"); } private static MethodInfo? findMethod(Type effectType) diff --git a/src/Wolverine/Persistence/Delete.cs b/src/Wolverine/Persistence/Delete.cs new file mode 100644 index 000000000..c101b4df2 --- /dev/null +++ b/src/Wolverine/Persistence/Delete.cs @@ -0,0 +1,33 @@ +using JasperFx.CodeGeneration; +using JasperFx.CodeGeneration.Frames; +using JasperFx.CodeGeneration.Model; +using Wolverine.Configuration; +using Wolverine.Persistence.Sagas; +using Wolverine.Runtime; +using Wolverine.Runtime.Handlers; + +namespace Wolverine.Persistence; + +/// +/// Return side effect value that deletes the wrapped entity into the underlying persistence mechanism +/// +/// +/// +public record Delete(T Entity) : ISideEffectAware, IStorageAction +{ + public static Frame BuildFrame(IChain chain, Variable variable, GenerationRules rules, + IServiceContainer container) + { + if (rules.TryFindPersistenceFrameProvider(container, typeof(T), out var provider)) + { + provider.ApplyTransactionSupport(chain, container, typeof(T)); + var value = new EntityVariable(variable); + return provider.DetermineDeleteFrame(value, container).WrapIfNotNull(variable); + } + + throw new NoMatchingPersistenceProviderException(typeof(T)); + + } + + public StorageAction Action => StorageAction.Delete; +} \ No newline at end of file diff --git a/src/Wolverine/Persistence/EntityAttribute.cs b/src/Wolverine/Persistence/EntityAttribute.cs new file mode 100644 index 000000000..aded674fc --- /dev/null +++ b/src/Wolverine/Persistence/EntityAttribute.cs @@ -0,0 +1,151 @@ +using System.Reflection; +using JasperFx.CodeGeneration; +using JasperFx.CodeGeneration.Frames; +using JasperFx.CodeGeneration.Model; +using JasperFx.Core; +using JasperFx.Core.Reflection; +using Wolverine.Attributes; +using Wolverine.Configuration; +using Wolverine.Persistence.Sagas; +using Wolverine.Runtime; + +namespace Wolverine.Persistence; + +/// +/// Use this when you absolutely have to keep a number of Frames together +/// and not allowing the topological sort to break them up +/// +internal class LoadEntityFrameBlock : Frame +{ + private readonly Frame[] _guardFrames; + private readonly Frame _creator; + + public LoadEntityFrameBlock(Variable entity, params Frame[] guardFrames) : base(entity.Creator.IsAsync || guardFrames.Any(x => x.IsAsync)) + { + _guardFrames = guardFrames; + Mirror = new Variable(entity.VariableType, entity.Usage, this); + _creator = entity.Creator; + } + + public Variable Mirror { get; } + + public override IEnumerable Creates => [Mirror]; + + public override void GenerateCode(GeneratedMethod method, ISourceWriter writer) + { + var previous = _creator; + foreach (var next in _guardFrames) + { + previous.Next = next; + previous = next; + } + + _creator.GenerateCode(method, writer); + + Next?.GenerateCode(method, writer); + } + + public override IEnumerable FindVariables(IMethodVariables chain) + { + return _creator + .FindVariables(chain) + .Concat(_guardFrames.SelectMany(x => x.FindVariables(chain))).Distinct(); + } + + public override bool CanReturnTask() + { + if (_guardFrames.Any()) return _guardFrames.Last().CanReturnTask(); + + return _creator.CanReturnTask(); + } +} + +/// +/// Apply this on a message handler method, an HTTP endpoint method, or any "before" middleware method parameter +/// to direct Wolverine to use a known persistence strategy to resolve the entity from the request or message +/// +public class EntityAttribute : WolverineParameterAttribute +{ + public EntityAttribute() + { + ValueSource = ValueSource.Anything; + } + + public EntityAttribute(string argumentName) : base(argumentName) + { + ValueSource = ValueSource.Anything; + } + + /// + /// Is the existence of this entity required for the rest of the handler action or HTTP endpoint + /// execution to continue? Default is true. + /// + public bool Required { get; set; } = true; + + public override Variable Modify(IChain chain, ParameterInfo parameter, IServiceContainer container, + GenerationRules rules) + { + if (!rules.TryFindPersistenceFrameProvider(container, parameter.ParameterType, out var provider)) + { + throw new InvalidOperationException("Could not determine a matching persistence service for entity " + + parameter.ParameterType.FullNameInCode()); + + } + + // I know it's goofy that this refers to the saga, but it should work fine here too + var idType = provider.DetermineSagaIdType(parameter.ParameterType, container); + + + + if (!tryFindIdentityVariable(chain, parameter, idType, out var identity)) + { + throw new InvalidEntityLoadUsageException(this, parameter); + } + + if (identity.Creator != null) + { + chain.Middleware.Add(identity.Creator); + } + + var frame = provider.DetermineLoadFrame(container, parameter.ParameterType, identity); + + var entity = frame.Creates.First(x => x.VariableType == parameter.ParameterType); + + if (Required) + { + var otherFrames = chain.AddStopConditionIfNull(entity); + + var block = new LoadEntityFrameBlock(entity, otherFrames); + chain.Middleware.Add(block); + + return block.Mirror; + } + + chain.Middleware.Add(frame); + return entity; + } + + private bool tryFindIdentityVariable(IChain chain, ParameterInfo parameter, Type idType, out Variable variable) + { + if (ArgumentName.IsNotEmpty()) + { + if (chain.TryFindVariable(ArgumentName, ValueSource, idType, out variable)) + { + return true; + } + } + + if (chain.TryFindVariable(parameter.ParameterType.Name + "Id", ValueSource, idType, out variable)) + { + return true; + } + + if (chain.TryFindVariable("Id", ValueSource, idType, out variable)) + { + return true; + } + + variable = default; + return false; + } +} \ No newline at end of file diff --git a/src/Wolverine/Persistence/EntityVariable.cs b/src/Wolverine/Persistence/EntityVariable.cs new file mode 100644 index 000000000..c4be9c663 --- /dev/null +++ b/src/Wolverine/Persistence/EntityVariable.cs @@ -0,0 +1,10 @@ +using JasperFx.CodeGeneration.Model; + +namespace Wolverine.Persistence; + +internal class EntityVariable : Variable +{ + public EntityVariable(Variable sideEffect) : base(sideEffect.VariableType.GetGenericArguments()[0], $"{sideEffect.Usage}.Entity") + { + } +} \ No newline at end of file diff --git a/src/Wolverine/Persistence/IPersistenceFrameProvider.cs b/src/Wolverine/Persistence/IPersistenceFrameProvider.cs index b3f612731..efa50cab1 100644 --- a/src/Wolverine/Persistence/IPersistenceFrameProvider.cs +++ b/src/Wolverine/Persistence/IPersistenceFrameProvider.cs @@ -8,6 +8,7 @@ namespace Wolverine.Persistence; public interface IPersistenceFrameProvider { void ApplyTransactionSupport(IChain chain, IServiceContainer container); + void ApplyTransactionSupport(IChain chain, IServiceContainer container, Type entityType); bool CanApply(IChain chain, IServiceContainer container); /// @@ -25,6 +26,26 @@ public interface IPersistenceFrameProvider Frame CommitUnitOfWorkFrame(Variable saga, IServiceContainer container); Frame DetermineUpdateFrame(Variable saga, IServiceContainer container); Frame DetermineDeleteFrame(Variable sagaId, Variable saga, IServiceContainer container); + + /// + /// Create an "upsert" Frame for the variable. Not every persistence provider will be able to support this + /// and should throw NotSupportedException if it does not + /// + /// + /// + /// + Frame DetermineStoreFrame(Variable variable, IServiceContainer container); + + /// + /// Create a delete Frame for the variable, not every persistence provider will be able to support this + /// and should throw NotSupportedException if it does not + /// + /// + /// + /// + Frame DetermineDeleteFrame(Variable variable, IServiceContainer container); + + Frame DetermineStorageActionFrame(Type entityType, Variable action, IServiceContainer container); } public interface ISagaOperation diff --git a/src/Wolverine/Persistence/IStorageAction.cs b/src/Wolverine/Persistence/IStorageAction.cs new file mode 100644 index 000000000..e60744fd4 --- /dev/null +++ b/src/Wolverine/Persistence/IStorageAction.cs @@ -0,0 +1,134 @@ +using JasperFx.CodeGeneration; +using JasperFx.CodeGeneration.Frames; +using JasperFx.CodeGeneration.Model; +using Wolverine.Configuration; +using Wolverine.Persistence.Sagas; +using Wolverine.Runtime; +using Wolverine.Runtime.Handlers; + +namespace Wolverine.Persistence; + +/// +/// Marks a return value as potentially modifying the wrapped entity in the underlying persistence +/// +/// +public interface IStorageAction : ISideEffectAware +{ + StorageAction Action { get; } + T Entity { get; } + + static Frame ISideEffectAware.BuildFrame(IChain chain, Variable variable, GenerationRules rules, IServiceContainer container) + { + if (rules.TryFindPersistenceFrameProvider(container, typeof(T), out var provider)) + { + provider.ApplyTransactionSupport(chain, container, typeof(T)); + var value = new EntityVariable(variable); + return provider.DetermineStorageActionFrame(typeof(T), value, container).WrapIfNotNull(variable); + } + + throw new NoMatchingPersistenceProviderException(typeof(T)); + } +} + +/// +/// Special side effect return type for Wolverine when you want to carry out zero +/// to many storage actions of the same entity type +/// +/// +public class UnitOfWork : List>, ISideEffectAware +{ + /// + /// "Upsert" an entity. Note that not every persistence tool natively supports + /// upsert operations + /// + /// + /// + /// + public UnitOfWork Store(T entity) + { + Add(Storage.Store(entity)); + return this; + } + + /// + /// "Insert" a new entity to the underlying persistence mechanism + /// + /// + /// + /// + public UnitOfWork Insert(T entity) + { + Add(Storage.Insert(entity)); + return this; + } + + /// + /// "Update" the entity into the underlying persistence mechanism + /// + /// + /// + /// + public UnitOfWork Update(T entity) + { + Add(Storage.Update(entity)); + return this; + } + + /// + /// "Delete" the entity in the underlying persistence mechanism + /// + /// + /// + /// + public UnitOfWork Delete(T entity) + { + Add(Storage.Delete(entity)); + return this; + } + + public static Frame BuildFrame(IChain chain, Variable variable, GenerationRules rules, IServiceContainer container) + { + if (rules.TryFindPersistenceFrameProvider(container, typeof(T), out var provider)) + { + provider.ApplyTransactionSupport(chain, container, typeof(T)); + var element = new Variable(typeof(T), "item_of_" + variable.Usage); + var inner = provider.DetermineStorageActionFrame(typeof(T), element, container); + + return new ForEachStorageActionFrame(variable, element, inner).WrapIfNotNull(variable); + } + + throw new NoMatchingPersistenceProviderException(typeof(T)); + } +} + +internal class ForEachStorageActionFrame : Frame +{ + private readonly Variable _collection; + private readonly Variable _element; + private readonly Frame _inner; + + public ForEachStorageActionFrame(Variable collection, Variable element, Frame inner) : base(inner.IsAsync) + { + _collection = collection; + _element = element; + _inner = inner; + } + + public override IEnumerable FindVariables(IMethodVariables chain) + { + yield return _collection; + foreach (var inner in _inner.FindVariables(chain)) + { + yield return inner; + } + } + + public override void GenerateCode(GeneratedMethod method, ISourceWriter writer) + { + writer.Write($"BLOCK:foreach (var {_element.Usage} in {_collection.Usage})"); + _inner.GenerateCode(method, writer); + writer.FinishBlock(); + + Next?.GenerateCode(method, writer); + } +} \ No newline at end of file diff --git a/src/Wolverine/Persistence/Insert.cs b/src/Wolverine/Persistence/Insert.cs new file mode 100644 index 000000000..f42cc2aee --- /dev/null +++ b/src/Wolverine/Persistence/Insert.cs @@ -0,0 +1,32 @@ +using JasperFx.CodeGeneration; +using JasperFx.CodeGeneration.Frames; +using JasperFx.CodeGeneration.Model; +using Wolverine.Configuration; +using Wolverine.Persistence.Sagas; +using Wolverine.Runtime; +using Wolverine.Runtime.Handlers; + +namespace Wolverine.Persistence; + +/// +/// Return side effect value that inserts the wrapped entity into the underlying persistence mechanism +/// +/// +/// +public record Insert(T Entity) : ISideEffectAware, IStorageAction +{ + public static Frame BuildFrame(IChain chain, Variable variable, GenerationRules rules, + IServiceContainer container) + { + if (rules.TryFindPersistenceFrameProvider(container, typeof(T), out var provider)) + { + provider.ApplyTransactionSupport(chain, container, typeof(T)); + var value = new EntityVariable(variable); + return provider.DetermineInsertFrame(value, container).WrapIfNotNull(variable); + } + + throw new NoMatchingPersistenceProviderException(typeof(T)); + } + + public StorageAction Action => StorageAction.Insert; +} \ No newline at end of file diff --git a/src/Wolverine/Persistence/InvalidEntityLoadUsageException.cs b/src/Wolverine/Persistence/InvalidEntityLoadUsageException.cs new file mode 100644 index 000000000..dfc8a42d4 --- /dev/null +++ b/src/Wolverine/Persistence/InvalidEntityLoadUsageException.cs @@ -0,0 +1,11 @@ +using System.Reflection; +using JasperFx.Core.Reflection; + +namespace Wolverine.Persistence; + +public class InvalidEntityLoadUsageException : Exception +{ + public InvalidEntityLoadUsageException(EntityAttribute att, ParameterInfo parameter) : base($"Unable to determine a value variable named '{att.ArgumentName}' and source {att.ValueSource} to load an entity of type {parameter.ParameterType.FullNameInCode()} for parameter {parameter.Name}") + { + } +} \ No newline at end of file diff --git a/src/Wolverine/Persistence/NoMatchingPersistenceProviderException.cs b/src/Wolverine/Persistence/NoMatchingPersistenceProviderException.cs new file mode 100644 index 000000000..7deb4ed2b --- /dev/null +++ b/src/Wolverine/Persistence/NoMatchingPersistenceProviderException.cs @@ -0,0 +1,10 @@ +using JasperFx.Core.Reflection; + +namespace Wolverine.Persistence; + +public class NoMatchingPersistenceProviderException : Exception +{ + public NoMatchingPersistenceProviderException(Type entityType) : base($"Wolverine is unable to determine a persistence provider for entity type {entityType.FullNameInCode()}") + { + } +} \ No newline at end of file diff --git a/src/Wolverine/Persistence/Nothing.cs b/src/Wolverine/Persistence/Nothing.cs new file mode 100644 index 000000000..ad9b99e3e --- /dev/null +++ b/src/Wolverine/Persistence/Nothing.cs @@ -0,0 +1,18 @@ +using JasperFx.CodeGeneration; +using JasperFx.CodeGeneration.Frames; +using JasperFx.CodeGeneration.Model; +using Wolverine.Configuration; +using Wolverine.Runtime; + +namespace Wolverine.Persistence; + +public record Nothing : IStorageAction +{ + public static Frame BuildFrame(IChain chain, Variable variable, GenerationRules rules, IServiceContainer container) + { + return new CommentFrame("Do nothing with the entity"); + } + + public StorageAction Action => StorageAction.Nothing; + public T Entity => default!; +} \ No newline at end of file diff --git a/src/Wolverine/Persistence/Sagas/GenerationRulesExtensions.cs b/src/Wolverine/Persistence/Sagas/GenerationRulesExtensions.cs index 3e472df2a..1a6e27d0d 100644 --- a/src/Wolverine/Persistence/Sagas/GenerationRulesExtensions.cs +++ b/src/Wolverine/Persistence/Sagas/GenerationRulesExtensions.cs @@ -49,6 +49,33 @@ public static class GenerationRulesExtensions } } + /// + /// Tries to find a persistence frame provider for the given entityType + /// + /// + /// + /// + /// + /// + public static bool TryFindPersistenceFrameProvider(this GenerationRules rules, IServiceContainer container, Type entityType, + out IPersistenceFrameProvider provider) + { + provider = default; + var providers = rules.PersistenceProviders(); + if (providers.Any()) + { + var candidates = providers.Where(x => x.CanPersist(entityType, container, out var _)).ToArray(); + + if (candidates.Any()) + { + provider = candidates.First(); + return true; + } + } + + return false; + } + public static List PersistenceProviders(this GenerationRules rules) { if (rules.Properties.TryGetValue(PersistenceKey, out var raw) && diff --git a/src/Wolverine/Persistence/Sagas/InMemoryPersistenceFrameProvider.cs b/src/Wolverine/Persistence/Sagas/InMemoryPersistenceFrameProvider.cs index 03250bf36..965ea6382 100644 --- a/src/Wolverine/Persistence/Sagas/InMemoryPersistenceFrameProvider.cs +++ b/src/Wolverine/Persistence/Sagas/InMemoryPersistenceFrameProvider.cs @@ -1,4 +1,5 @@ -using JasperFx.CodeGeneration.Frames; +using System.Reflection; +using JasperFx.CodeGeneration.Frames; using JasperFx.CodeGeneration.Model; using JasperFx.Core.Reflection; using Wolverine.Configuration; @@ -13,6 +14,11 @@ public void ApplyTransactionSupport(IChain chain, IServiceContainer container) // Nothing } + public void ApplyTransactionSupport(IChain chain, IServiceContainer container, Type entityType) + { + // Nothing + } + public bool CanApply(IChain chain, IServiceContainer container) { return false; @@ -74,6 +80,10 @@ public Frame DetermineDeleteFrame(Variable sagaId, Variable saga, IServiceContai { var method = typeof(InMemorySagaPersistor).GetMethod(nameof(InMemorySagaPersistor.Delete))! .MakeGenericMethod(saga.VariableType); + + // This guy is pretty limited + sagaId ??= new Variable(typeof(object), $"{saga.Usage}.Id"); + var call = new MethodCall(typeof(InMemorySagaPersistor), method) { Arguments = @@ -84,4 +94,28 @@ public Frame DetermineDeleteFrame(Variable sagaId, Variable saga, IServiceContai return call; } + + public Frame DetermineStoreFrame(Variable variable, IServiceContainer container) + { + return DetermineInsertFrame(variable, container); + } + + public Frame DetermineDeleteFrame(Variable variable, IServiceContainer container) + { + return DetermineDeleteFrame(null, variable, container); + } + + public Frame DetermineStorageActionFrame(Type entityType, Variable action, IServiceContainer container) + { + var call = typeof(InMemorySagaPersistorStore<>).CloseAndBuildAs(entityType); + call.Arguments[0] = action; + return call; + } +} + +internal class InMemorySagaPersistorStore : MethodCall +{ + public InMemorySagaPersistorStore() : base(typeof(InMemorySagaPersistor), ReflectionHelper.GetMethod(x => x.StoreAction(Storage.Nothing()))) + { + } } \ No newline at end of file diff --git a/src/Wolverine/Persistence/Sagas/InMemorySagaPersistor.cs b/src/Wolverine/Persistence/Sagas/InMemorySagaPersistor.cs index d7261cf58..f775672cf 100644 --- a/src/Wolverine/Persistence/Sagas/InMemorySagaPersistor.cs +++ b/src/Wolverine/Persistence/Sagas/InMemorySagaPersistor.cs @@ -47,4 +47,22 @@ public void Delete(object id) var key = ToKey(typeof(T), id); _data.TryRemove(key, out _); } + + public void StoreAction(IStorageAction action) + { + switch (action.Action) + { + case StorageAction.Delete: + var idProp = typeof(T).GetProperty("Id"); + var id = idProp.GetValue(action.Entity); + Delete(id); + break; + + case StorageAction.Insert: + case StorageAction.Store: + case StorageAction.Update: + Store(action.Entity); + break; + } + } } \ No newline at end of file diff --git a/src/Wolverine/Persistence/Storage.cs b/src/Wolverine/Persistence/Storage.cs new file mode 100644 index 000000000..5c91f8c59 --- /dev/null +++ b/src/Wolverine/Persistence/Storage.cs @@ -0,0 +1,75 @@ +using JasperFx.CodeGeneration; +using JasperFx.CodeGeneration.Model; +using JasperFx.Core.Reflection; +using Wolverine.Configuration; +using Wolverine.Persistence.Sagas; +using Wolverine.Runtime; +using Wolverine.Runtime.Handlers; + +namespace Wolverine.Persistence; + +/// +/// Convenience class to build storage actions for return values on Wolverine handler methods +/// or http endpoint methods +/// +public static class Storage +{ + /// + /// "Upsert" an entity. Note that not every persistence tool natively supports + /// upsert operations + /// + /// + /// + /// + public static Store Store(T entity) => new(entity); + + /// + /// "Insert" a new entity to the underlying persistence mechanism + /// + /// + /// + /// + public static Insert Insert(T entity) => new(entity); + + /// + /// "Update" the entity into the underlying persistence mechanism + /// + /// + /// + /// + public static Update Update(T entity) => new(entity); + + /// + /// "Delete" the entity in the underlying persistence mechanism + /// + /// + /// + /// + public static Delete Delete(T entity) => new(entity); + + /// + /// Do absolutely nothing with this entity + /// + /// + /// + public static Nothing Nothing() => new(); + + internal static bool TryApply(Variable effect, GenerationRules rules, IServiceContainer container, IChain chain) + { + if (effect.VariableType.Closes(typeof(IStorageAction<>)) && + effect.VariableType.GetGenericTypeDefinition() == typeof(IStorageAction<>)) + { + var entityType = effect.VariableType.GetGenericArguments()[0]; + if (rules.TryFindPersistenceFrameProvider(container, entityType, out var provider)) + { + effect.UseReturnAction(v => provider.DetermineStorageActionFrame(entityType, effect, container).WrapIfNotNull(effect)); + provider.ApplyTransactionSupport(chain, container, entityType); + return true; + } + + throw new NoMatchingPersistenceProviderException(entityType); + } + + return false; + } +} \ No newline at end of file diff --git a/src/Wolverine/Persistence/StorageAction.cs b/src/Wolverine/Persistence/StorageAction.cs new file mode 100644 index 000000000..ad27dcd91 --- /dev/null +++ b/src/Wolverine/Persistence/StorageAction.cs @@ -0,0 +1,29 @@ +namespace Wolverine.Persistence; + +public enum StorageAction +{ + /// + /// "Upsert" the entity + /// + Store, + + /// + /// Delete the entity + /// + Delete, + + /// + /// Do nothing to the entity + /// + Nothing, + + /// + /// Update the entity + /// + Update, + + /// + /// Insert the entity + /// + Insert +} \ No newline at end of file diff --git a/src/Wolverine/Persistence/StorageCommand.cs b/src/Wolverine/Persistence/StorageCommand.cs index 14e935830..16ce5026d 100644 --- a/src/Wolverine/Persistence/StorageCommand.cs +++ b/src/Wolverine/Persistence/StorageCommand.cs @@ -1,3 +1,4 @@ +using JasperFx.CodeGeneration.Model; using Microsoft.Extensions.DependencyInjection; using Oakton; using Spectre.Console; @@ -5,7 +6,7 @@ namespace Wolverine.Persistence; -public enum StorageAction +public enum StorageCommandAction { clear, counts, @@ -16,7 +17,7 @@ public enum StorageAction public class StorageInput : NetCoreInput { - [Description("Choose the action")] public StorageAction Action { get; set; } = StorageAction.counts; + [Description("Choose the action")] public StorageCommandAction Action { get; set; } = StorageCommandAction.counts; [Description("Optional, specify the file where the schema script would be written")] public string FileFlag { get; set; } = "storage.sql"; @@ -43,7 +44,7 @@ public override async Task Execute(StorageInput input) switch (input.Action) { - case StorageAction.counts: + case StorageCommandAction.counts: var counts = await persistence.Admin.FetchCountsAsync(); Console.WriteLine("Persisted Enveloper Counts"); @@ -59,25 +60,25 @@ public override async Task Execute(StorageInput input) break; - case StorageAction.clear: + case StorageCommandAction.clear: await persistence.Admin.ClearAllAsync(); await persistence.Nodes.ClearAllAsync(CancellationToken.None); AnsiConsole.Write("[green]Successfully deleted all persisted envelopes and existing node records[/]"); break; - case StorageAction.rebuild: + case StorageCommandAction.rebuild: await persistence.Admin.RebuildAsync(); AnsiConsole.Write("[green]Successfully rebuilt the envelope storage[/]"); break; - case StorageAction.release: + case StorageCommandAction.release: await persistence.Admin.RebuildAsync(); Console.WriteLine("Releasing all ownership of persisted envelopes"); await persistence.Admin.ReleaseAllOwnershipAsync(); break; - case StorageAction.replay: + case StorageCommandAction.replay: var markedCount = await persistence.DeadLetters.MarkDeadLetterEnvelopesAsReplayableAsync(input.ExceptionTypeForReplayFlag); var exceptionType = string.IsNullOrEmpty(input.ExceptionTypeForReplayFlag) diff --git a/src/Wolverine/Persistence/Store.cs b/src/Wolverine/Persistence/Store.cs new file mode 100644 index 000000000..a5e66007e --- /dev/null +++ b/src/Wolverine/Persistence/Store.cs @@ -0,0 +1,32 @@ +using JasperFx.CodeGeneration; +using JasperFx.CodeGeneration.Frames; +using JasperFx.CodeGeneration.Model; +using Wolverine.Configuration; +using Wolverine.Persistence.Sagas; +using Wolverine.Runtime; +using Wolverine.Runtime.Handlers; + +namespace Wolverine.Persistence; + +/// +/// Return side effect value that upserts the wrapped entity into the underlying persistence mechanism +/// +/// +/// +public record Store(T Entity) : ISideEffectAware, IStorageAction +{ + public static Frame BuildFrame(IChain chain, Variable variable, GenerationRules rules, + IServiceContainer container) + { + if (rules.TryFindPersistenceFrameProvider(container, typeof(T), out var provider)) + { + provider.ApplyTransactionSupport(chain, container, typeof(T)); + var value = new EntityVariable(variable); + return provider.DetermineStoreFrame(value, container).WrapIfNotNull(variable); + } + + throw new NoMatchingPersistenceProviderException(typeof(T)); + } + + public StorageAction Action => StorageAction.Store; +} \ No newline at end of file diff --git a/src/Wolverine/Persistence/Update.cs b/src/Wolverine/Persistence/Update.cs new file mode 100644 index 000000000..1c39706ce --- /dev/null +++ b/src/Wolverine/Persistence/Update.cs @@ -0,0 +1,33 @@ +using JasperFx.CodeGeneration; +using JasperFx.CodeGeneration.Frames; +using JasperFx.CodeGeneration.Model; +using Wolverine.Configuration; +using Wolverine.Persistence.Sagas; +using Wolverine.Runtime; +using Wolverine.Runtime.Handlers; + +namespace Wolverine.Persistence; + +/// +/// Return side effect value that updates the wrapped entity into the underlying persistence mechanism +/// +/// +/// +public record Update(T Entity) : ISideEffectAware, IStorageAction +{ + public static Frame BuildFrame(IChain chain, Variable variable, GenerationRules rules, + IServiceContainer container) + { + if (rules.TryFindPersistenceFrameProvider(container, typeof(T), out var provider)) + { + provider.ApplyTransactionSupport(chain, container, typeof(T)); + var value = new EntityVariable(variable); + var frame = provider.DetermineUpdateFrame(value, container).WrapIfNotNull(variable); + return frame; + } + + throw new NoMatchingPersistenceProviderException(typeof(T)); + } + + public StorageAction Action => StorageAction.Update; +} \ No newline at end of file diff --git a/src/Wolverine/Runtime/Handlers/HandlerChain.cs b/src/Wolverine/Runtime/Handlers/HandlerChain.cs index 5937bf052..2741ec688 100644 --- a/src/Wolverine/Runtime/Handlers/HandlerChain.cs +++ b/src/Wolverine/Runtime/Handlers/HandlerChain.cs @@ -9,9 +9,11 @@ using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Wolverine.Attributes; +using Wolverine.Codegen; using Wolverine.Configuration; using Wolverine.ErrorHandling; using Wolverine.Logging; +using Wolverine.Middleware; using Wolverine.Persistence; using Wolverine.Runtime.Routing; using Wolverine.Transports.Local; @@ -324,6 +326,33 @@ public override void UseForResponse(MethodCall methodCall) Postprocessors.Add(cascading); } + public override bool TryFindVariable(string valueName, ValueSource source, Type valueType, out Variable variable) + { + if (source == ValueSource.InputMember || source == ValueSource.Anything) + { + var member = MessageType.GetProperties() + .FirstOrDefault(x => x.Name.EqualsIgnoreCase(valueName) && x.PropertyType == valueType) + ?? (MemberInfo)MessageType.GetFields() + .FirstOrDefault(x => x.Name.EqualsIgnoreCase(valueName) && x.FieldType == valueType); + + if (member != null) + { + variable = new MessageMemberVariable(member, MessageType); + return true; + } + } + + variable = default; + return false; + } + + public override Frame[] AddStopConditionIfNull(Variable variable) + { + var frame = typeof(EntityIsNotNullGuardFrame<>).CloseAndBuildAs(variable, variable.VariableType); + + return [frame, new HandlerContinuationFrame(frame)]; + } + public IEnumerable PublishedTypes() { var ignoredTypes = new[] @@ -444,14 +473,26 @@ protected void applyCustomizations(GenerationRules rules, IServiceContainer cont foreach (var attribute in MessageType.GetCustomAttributes(typeof(ModifyChainAttribute)) .OfType()) attribute.Modify(this, rules, container); + + foreach (var handlerCall in HandlerCalls()) + { + WolverineParameterAttribute.TryApply(handlerCall, container, rules, this); + } } ApplyImpliedMiddlewareFromHandlers(rules); + + // Use Wolverine Parameter Attribute on any middleware + foreach (var methodCall in Middleware.OfType().ToArray()) + { + WolverineParameterAttribute.TryApply(methodCall, container, rules, this); + } } protected IEnumerable determineHandlerReturnValueFrames() { return Handlers.SelectMany(x => x.Creates) + .Where( x => x is not MemberAccessVariable) .Select(x => x.ReturnAction(this)) .SelectMany(x => x.Frames()); } @@ -493,4 +534,27 @@ internal TimeSpan DetermineMessageTimeout(WolverineOptions options) return options.DefaultExecutionTimeout; } +} + +internal class EntityIsNotNullGuardFrame : MethodCall +{ + public EntityIsNotNullGuardFrame(Variable variable) : base(typeof(EntityIsNotNullGuard), "Assert") + { + Arguments[0] = variable; + Arguments[2] = Constant.For(variable.Usage); + } +} + +public static class EntityIsNotNullGuard +{ + public static HandlerContinuation Assert(T entity, ILogger logger, string entityVariableName, Envelope envelope) + { + if (entity == null) + { + logger.LogInformation("Not processing envelope {Id} because the required entity {EntityType} ('{VariableName}') cannot be found", envelope.Id, typeof(T).FullNameInCode(), entityVariableName); + return HandlerContinuation.Stop; + } + + return HandlerContinuation.Continue; + } } \ No newline at end of file