diff --git a/docs/guide/http/endpoints.md b/docs/guide/http/endpoints.md index b5ed6aefa..6f2ad70e2 100644 --- a/docs/guide/http/endpoints.md +++ b/docs/guide/http/endpoints.md @@ -428,4 +428,11 @@ There is no runtime filtering here because the `MiddlewareScoping` impacts the g HTTP endpoint method, and Wolverine already generates code separately for the two use cases. ::: +As of Wolverine 5.7, you can also technically use `HttpContext` arguments in the message handler usage *if* +you are carefully accounting for that being null as shown in this sample: + +snippet: sample_HybridHandler_with_null_HttpContext + + + diff --git a/src/Http/Wolverine.Http.Tests/combo_handler_and_endpoint.cs b/src/Http/Wolverine.Http.Tests/combo_handler_and_endpoint.cs index 856fb2dc2..9005fd852 100644 --- a/src/Http/Wolverine.Http.Tests/combo_handler_and_endpoint.cs +++ b/src/Http/Wolverine.Http.Tests/combo_handler_and_endpoint.cs @@ -1,6 +1,7 @@ using Alba; using Microsoft.AspNetCore.Mvc; using Shouldly; +using Wolverine.Tracking; using WolverineWebApi; namespace Wolverine.Http.Tests; @@ -63,4 +64,17 @@ public async Task use_combo_as_handler_see_problem_details_catch() NumberMessageHandler.CalledBeforeOnlyOnHttpEndpoints.ShouldBeFalse(); NumberMessageHandler.CalledBeforeOnlyOnMessageHandlers.ShouldBeTrue(); } + + [Fact] + public async Task will_not_go_bonkers_with_nullable_http_context() + { + var response = await Host.Scenario(x => + { + x.Post.Json(new DoHybrid("go, go gadget")).ToUrl("/hybrid"); + }); + + response.ReadAsText().ShouldBe("go, go gadget"); + + await Host.InvokeMessageAndWaitAsync(new DoHybrid("now as a handler")); + } } \ No newline at end of file diff --git a/src/Http/Wolverine.Http/CodeGen/NullableHttpContextSource.cs b/src/Http/Wolverine.Http/CodeGen/NullableHttpContextSource.cs new file mode 100644 index 000000000..20b929b52 --- /dev/null +++ b/src/Http/Wolverine.Http/CodeGen/NullableHttpContextSource.cs @@ -0,0 +1,18 @@ +using JasperFx.CodeGeneration.Model; +using Microsoft.AspNetCore.Http; + +namespace Wolverine.Http.CodeGen; + +internal class NullableHttpContextSource : IVariableSource +{ + public bool Matches(Type type) + { + return type == typeof(HttpContext); + } + + public Variable Create(Type type) + { + return new Variable(typeof(HttpContext), "null"); + } +} + diff --git a/src/Http/Wolverine.Http/WolverineHttpEndpointRouteBuilderExtensions.cs b/src/Http/Wolverine.Http/WolverineHttpEndpointRouteBuilderExtensions.cs index 153a8a86a..133bb290d 100644 --- a/src/Http/Wolverine.Http/WolverineHttpEndpointRouteBuilderExtensions.cs +++ b/src/Http/Wolverine.Http/WolverineHttpEndpointRouteBuilderExtensions.cs @@ -158,6 +158,12 @@ public static IServiceCollection AddWolverineHttp(this IServiceCollection servic services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); + + services.ConfigureWolverine(opts => + { + opts.CodeGeneration.Sources.Add(new NullableHttpContextSource()); + }); + return services; } diff --git a/src/Http/WolverineWebApi/HybridHandler.cs b/src/Http/WolverineWebApi/HybridHandler.cs new file mode 100644 index 000000000..1c1e32a3a --- /dev/null +++ b/src/Http/WolverineWebApi/HybridHandler.cs @@ -0,0 +1,24 @@ +using Wolverine.Http; + +namespace WolverineWebApi; + +#region sample_HybridHandler_with_null_HttpContext + +public record DoHybrid(string Message); + +public static class HybridHandler +{ + [WolverinePost("/hybrid")] + public static async Task HandleAsync(DoHybrid command, HttpContext? context) + { + // What this, because it will be null if this is used within + // a message handler! + if (context != null) + { + context.Response.ContentType = "text/plain"; + await context.Response.WriteAsync(command.Message); + } + } +} + +#endregion \ No newline at end of file