diff --git a/src/Http/Wolverine.Http.Tests/Bugs/Bug_1961_reserved_characters_in_form_field.cs b/src/Http/Wolverine.Http.Tests/Bugs/Bug_1961_reserved_characters_in_form_field.cs new file mode 100644 index 000000000..c61a340cd --- /dev/null +++ b/src/Http/Wolverine.Http.Tests/Bugs/Bug_1961_reserved_characters_in_form_field.cs @@ -0,0 +1,68 @@ +using Alba; +using IntegrationTests; +using Marten; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; +using Wolverine.Marten; + +namespace Wolverine.Http.Tests.Bugs; + +public class Bug_1961_reserved_characters_in_form_field +{ + [Fact] + public async Task generate_code_correctly() + { + + var builder = WebApplication.CreateBuilder([]); + + builder.Services.AddMarten(opts => + { + // Establish the connection string to your Marten database + opts.Connection(Servers.PostgresConnectionString); + opts.DisableNpgsqlLogging = true; + }).IntegrateWithWolverine(); + + builder.Host.UseWolverine(opts => + { + opts.Discovery.DisableConventionalDiscovery().IncludeType(typeof(TrainingRequestHandler)); + opts.ApplicationAssembly = GetType().Assembly; + }); + + builder.Services.AddWolverineHttp(); + + // This is using Alba, which uses WebApplicationFactory under the covers + await using var host = await AlbaHost.For(builder, app => + { + app.MapWolverineEndpoints(x => + { + + }); + }); + + var result = await host.Scenario(x => + { + x.Post.FormData(new (){ { "rechtliche_hinweise/akzeptiert", "Albert" } }) + .ToUrl("/angebot/training"); + + x.StatusCodeShouldBe(302); + }); + } +} + +// For https://github.com/JasperFx/wolverine/issues/1961 +public record TrainingRequest( + [FromForm(Name = "rechtliche_hinweise/akzeptiert")] + bool? rechtlicheHinweiseAkzeptiert +); + +public static class TrainingRequestHandler +{ + [WolverinePost("angebot/training")] + public static IResult Post([AsParameters()]TrainingRequest egal) + + { + return Results.Redirect($"/vielen-dank"); + } + +} \ No newline at end of file diff --git a/src/Http/Wolverine.Http.Tests/Internal/Generated/WolverineHandlers/GET_todo_id.cs b/src/Http/Wolverine.Http.Tests/Internal/Generated/WolverineHandlers/GET_todo_id.cs index db0ae92cf..228bf9b94 100644 --- a/src/Http/Wolverine.Http.Tests/Internal/Generated/WolverineHandlers/GET_todo_id.cs +++ b/src/Http/Wolverine.Http.Tests/Internal/Generated/WolverineHandlers/GET_todo_id.cs @@ -14,14 +14,14 @@ namespace Internal.Generated.WolverineHandlers public sealed class GET_todo_id : Wolverine.Http.HttpHandler { private readonly Wolverine.Http.WolverineHttpOptions _wolverineHttpOptions; - private readonly Wolverine.Marten.Publishing.OutboxedSessionFactory _outboxedSessionFactory; private readonly Wolverine.Runtime.IWolverineRuntime _wolverineRuntime; + private readonly Wolverine.Marten.Publishing.OutboxedSessionFactory _outboxedSessionFactory; - public GET_todo_id(Wolverine.Http.WolverineHttpOptions wolverineHttpOptions, Wolverine.Marten.Publishing.OutboxedSessionFactory outboxedSessionFactory, Wolverine.Runtime.IWolverineRuntime wolverineRuntime) : base(wolverineHttpOptions) + public GET_todo_id(Wolverine.Http.WolverineHttpOptions wolverineHttpOptions, Wolverine.Runtime.IWolverineRuntime wolverineRuntime, Wolverine.Marten.Publishing.OutboxedSessionFactory outboxedSessionFactory) : base(wolverineHttpOptions) { _wolverineHttpOptions = wolverineHttpOptions; - _outboxedSessionFactory = outboxedSessionFactory; _wolverineRuntime = wolverineRuntime; + _outboxedSessionFactory = outboxedSessionFactory; } diff --git a/src/Http/Wolverine.Http.Tests/Internal/Generated/WolverineHandlers/POST_todo_create.cs b/src/Http/Wolverine.Http.Tests/Internal/Generated/WolverineHandlers/POST_todo_create.cs index 01f4e49d1..9fdae9fa5 100644 --- a/src/Http/Wolverine.Http.Tests/Internal/Generated/WolverineHandlers/POST_todo_create.cs +++ b/src/Http/Wolverine.Http.Tests/Internal/Generated/WolverineHandlers/POST_todo_create.cs @@ -14,14 +14,14 @@ namespace Internal.Generated.WolverineHandlers public sealed class POST_todo_create : Wolverine.Http.HttpHandler { private readonly Wolverine.Http.WolverineHttpOptions _wolverineHttpOptions; - private readonly Wolverine.Marten.Publishing.OutboxedSessionFactory _outboxedSessionFactory; private readonly Wolverine.Runtime.IWolverineRuntime _wolverineRuntime; + private readonly Wolverine.Marten.Publishing.OutboxedSessionFactory _outboxedSessionFactory; - public POST_todo_create(Wolverine.Http.WolverineHttpOptions wolverineHttpOptions, Wolverine.Marten.Publishing.OutboxedSessionFactory outboxedSessionFactory, Wolverine.Runtime.IWolverineRuntime wolverineRuntime) : base(wolverineHttpOptions) + public POST_todo_create(Wolverine.Http.WolverineHttpOptions wolverineHttpOptions, Wolverine.Runtime.IWolverineRuntime wolverineRuntime, Wolverine.Marten.Publishing.OutboxedSessionFactory outboxedSessionFactory) : base(wolverineHttpOptions) { _wolverineHttpOptions = wolverineHttpOptions; - _outboxedSessionFactory = outboxedSessionFactory; _wolverineRuntime = wolverineRuntime; + _outboxedSessionFactory = outboxedSessionFactory; } diff --git a/src/Http/Wolverine.Http.Tests/asparameters_binding.cs b/src/Http/Wolverine.Http.Tests/asparameters_binding.cs index d87a3d571..78667cf6e 100644 --- a/src/Http/Wolverine.Http.Tests/asparameters_binding.cs +++ b/src/Http/Wolverine.Http.Tests/asparameters_binding.cs @@ -2,6 +2,7 @@ using Microsoft.Extensions.DependencyInjection; using Shouldly; using WolverineWebApi; +using WolverineWebApi.Forms; namespace Wolverine.Http.Tests; diff --git a/src/Http/Wolverine.Http.Tests/using_form_parameters.cs b/src/Http/Wolverine.Http.Tests/using_form_parameters.cs index e6a2fe88f..ff2d4c550 100644 --- a/src/Http/Wolverine.Http.Tests/using_form_parameters.cs +++ b/src/Http/Wolverine.Http.Tests/using_form_parameters.cs @@ -5,6 +5,7 @@ using Wolverine.Http.CodeGen; using Wolverine.Runtime; using WolverineWebApi; +using WolverineWebApi.Forms; namespace Wolverine.Http.Tests; diff --git a/src/Http/Wolverine.Http/CodeGen/CodeGenExtensions.cs b/src/Http/Wolverine.Http/CodeGen/CodeGenExtensions.cs new file mode 100644 index 000000000..d23fd623d --- /dev/null +++ b/src/Http/Wolverine.Http/CodeGen/CodeGenExtensions.cs @@ -0,0 +1,9 @@ +namespace Wolverine.Http.CodeGen; + +internal static class CodeGenExtensions +{ + public static string SanitizeFormNameForVariable(this string variableName) + { + return variableName.Replace("/", "_"); + } +} \ No newline at end of file diff --git a/src/Http/Wolverine.Http/CodeGen/HttpElementVariable.cs b/src/Http/Wolverine.Http/CodeGen/HttpElementVariable.cs index ea01356b1..687ec7ed8 100644 --- a/src/Http/Wolverine.Http/CodeGen/HttpElementVariable.cs +++ b/src/Http/Wolverine.Http/CodeGen/HttpElementVariable.cs @@ -10,7 +10,7 @@ public class HttpElementVariable : Variable { public HttpElementVariable(Type variableType, string usage, Frame? creator) : base(variableType, usage, creator) { - Name = usage; + Name = usage.SanitizeFormNameForVariable(); } public string Name { get; set; } diff --git a/src/Http/Wolverine.Http/CodeGen/IReadHttpFrame.cs b/src/Http/Wolverine.Http/CodeGen/IReadHttpFrame.cs index 8fb8da59c..bd94c4be8 100644 --- a/src/Http/Wolverine.Http/CodeGen/IReadHttpFrame.cs +++ b/src/Http/Wolverine.Http/CodeGen/IReadHttpFrame.cs @@ -27,7 +27,7 @@ internal class ReadHttpFrame : SyncFrame, IReadHttpFrame public ReadHttpFrame(BindingSource source, Type parameterType, string parameterName, bool isOptional = false) { _source = source; - Variable = new HttpElementVariable(parameterType, parameterName!, this); + Variable = new HttpElementVariable(parameterType, parameterName!.SanitizeFormNameForVariable(), this); _isOptional = isOptional; _isNullable = parameterType.IsNullable(); diff --git a/src/Http/Wolverine.Http/HttpChain.cs b/src/Http/Wolverine.Http/HttpChain.cs index d2e29e508..2a6cc6f88 100644 --- a/src/Http/Wolverine.Http/HttpChain.cs +++ b/src/Http/Wolverine.Http/HttpChain.cs @@ -409,13 +409,11 @@ private void applyMetadata() if (parameterType == typeof(string)) { variable = new ReadHttpFrame(BindingSource.Form, parameterType,key).Variable; - variable.Name = key; _formValueVariables.Add(variable); } if (parameterType == typeof(string[])) { variable = new ParsedArrayFormValue(parameterType, parameterName).Variable; - variable.Name = key; _formValueVariables.Add(variable); } diff --git a/src/Http/WolverineWebApi/FormEndpoints.cs b/src/Http/WolverineWebApi/Forms/FormEndpoints.cs similarity index 99% rename from src/Http/WolverineWebApi/FormEndpoints.cs rename to src/Http/WolverineWebApi/Forms/FormEndpoints.cs index bb3499dbb..1b8ade198 100644 --- a/src/Http/WolverineWebApi/FormEndpoints.cs +++ b/src/Http/WolverineWebApi/Forms/FormEndpoints.cs @@ -4,10 +4,9 @@ using Marten; using Microsoft.AspNetCore.Mvc; using Shouldly; -using Spectre.Console; using Wolverine.Http; -namespace WolverineWebApi; +namespace WolverineWebApi.Forms; //Uses same test data as QuerystringEndpoints public static class FormEndpoints{