Skip to content

Commit

Permalink
Ensure use of InvariantCulture for query binding. Closes GH-524
Browse files Browse the repository at this point in the history
  • Loading branch information
alistair authored and jeremydmiller committed Sep 6, 2023
1 parent a07a675 commit 52ac749
Show file tree
Hide file tree
Showing 7 changed files with 86 additions and 6 deletions.
15 changes: 15 additions & 0 deletions src/Http/Wolverine.Http.Tests/end_to_end.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
using System.Globalization;
using System.Net.Http.Headers;
using Alba;
using Shouldly;
using WolverineWebApi;
Expand Down Expand Up @@ -208,6 +210,19 @@ public async Task use_string_querystring_miss()
body.ReadAsText().ShouldBe("Name is missing");
}

[Fact]
public async Task use_decimal_querystring_hit()
{
var body = await Scenario(x =>
{
x.WithRequestHeader("Accept-Language", "fr-FR");
x.Get.Url("/querystring/decimal?amount=42.1");
x.Header("content-type").SingleValueShouldEqual("text/plain");
});

body.ReadAsText().ShouldBe("Amount is 42.1");
}

#endregion
}

15 changes: 11 additions & 4 deletions src/Http/Wolverine.Http/CodeGen/QueryStringHandling.cs
Original file line number Diff line number Diff line change
Expand Up @@ -38,16 +38,19 @@ public override void GenerateCode(GeneratedMethod method, ISourceWriter writer)
var alias = Variable.VariableType.FullNameInCode();
writer.Write($"{alias} {Variable.Usage} = default;");


if (Variable.VariableType.IsEnum)
{
writer.Write($"{alias}.TryParse<{alias}>(httpContext.Request.Query[\"{Variable.Usage}\"], out {Variable.Usage});");
}
else
else if (Variable.VariableType.IsBoolean())
{
writer.Write($"{alias}.TryParse(httpContext.Request.Query[\"{Variable.Usage}\"], out {Variable.Usage});");
}


else
{
writer.Write($"{alias}.TryParse(httpContext.Request.Query[\"{Variable.Usage}\"], System.Globalization.CultureInfo.InvariantCulture, out {Variable.Usage});");
}

Next?.GenerateCode(method, writer);
}
Expand Down Expand Up @@ -75,10 +78,14 @@ public override void GenerateCode(GeneratedMethod method, ISourceWriter writer)
writer.Write(
$"if ({_alias}.TryParse<{_innerTypeFromNullable.FullNameInCode()}>(httpContext.Request.Query[\"{Variable.Usage}\"], out var {Variable.Usage}Parsed)) {Variable.Usage} = {Variable.Usage}Parsed;");
}
else if (_innerTypeFromNullable.IsBoolean())
{
writer.Write($"{_alias}.TryParse(httpContext.Request.Query[\"{Variable.Usage}\"], out {Variable.Usage});");
}
else
{
writer.Write(
$"if ({_alias}.TryParse(httpContext.Request.Query[\"{Variable.Usage}\"], out var {Variable.Usage}Parsed)) {Variable.Usage} = {Variable.Usage}Parsed;");
$"if ({_alias}.TryParse(httpContext.Request.Query[\"{Variable.Usage}\"], System.Globalization.CultureInfo.InvariantCulture, out var {Variable.Usage}Parsed)) {Variable.Usage} = {Variable.Usage}Parsed;");
}

Next?.GenerateCode(method, writer);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
// <auto-generated/>
#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
var result_of_UseQueryStringParsing = WolverineWebApi.TestEndpoints.UseQueryStringParsing(_recorder, amount);
await WriteString(httpContext, result_of_UseQueryStringParsing);
}

}

// END: GET_querystring_decimal


}

Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ public GET_querystring_int(Wolverine.Http.WolverineHttpOptions wolverineHttpOpti
public override async System.Threading.Tasks.Task Handle(Microsoft.AspNetCore.Http.HttpContext httpContext)
{
int? age = null;
if (int.TryParse(httpContext.Request.Query["age"], out var ageParsed)) age = ageParsed;
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
var result_of_UsingQueryStringParsing = WolverineWebApi.TestEndpoints.UsingQueryStringParsing(_recorder, age);
await WriteString(httpContext, result_of_UsingQueryStringParsing);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ public GET_querystring_int_nullable(Wolverine.Http.WolverineHttpOptions wolverin
public override async System.Threading.Tasks.Task Handle(Microsoft.AspNetCore.Http.HttpContext httpContext)
{
int? age = null;
if (int.TryParse(httpContext.Request.Query["age"], out var ageParsed)) age = ageParsed;
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
var result_of_UsingQueryStringParsingNullable = WolverineWebApi.TestEndpoints.UsingQueryStringParsingNullable(age);
await WriteString(httpContext, result_of_UsingQueryStringParsingNullable);
Expand Down
8 changes: 8 additions & 0 deletions src/Http/WolverineWebApi/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,14 @@

var app = builder.Build();

//Force the default culture to not be en-US to ensure code is culture agnostic
var supportedCultures = new[] { "fr-FR", "en-US" };
var localizationOptions = new RequestLocalizationOptions().SetDefaultCulture(supportedCultures[0])
.AddSupportedCultures(supportedCultures)
.AddSupportedUICultures(supportedCultures);

app.UseRequestLocalization(localizationOptions);

// Configure the HTTP request pipeline.
app.UseSwagger();
app.UseSwaggerUI();
Expand Down
10 changes: 10 additions & 0 deletions src/Http/WolverineWebApi/TestEndpoints.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
using System.Globalization;
using System.Linq.Expressions;
using Marten;
using Wolverine.Http;

Expand Down Expand Up @@ -70,6 +72,14 @@ public static string UsingQueryStringParsingNullable(int? age)
return $"Age is {age}";
}

[WolverineGet("/querystring/decimal")]
public static string UseQueryStringParsing(Recorder recorder, decimal amount)
{
recorder.Actions.Add("Got through query string usage for decimal");

return string.Format(CultureInfo.InvariantCulture, "Amount is {0}", amount);
}

#region sample_simple_wolverine_http_endpoint

[WolverinePost("/question")]
Expand Down

0 comments on commit 52ac749

Please sign in to comment.