fix: use InvariantCulture for decimal/DateTime parsing in gRPC

The generated gRPC service code was using locale-dependent parsing
for decimal and DateTime values. On French locale systems, this
caused FormatException when parsing "0.95" because the system
expected a comma as decimal separator.

Now uses CultureInfo.InvariantCulture for all decimal.Parse() and
DateTime.Parse() calls to ensure consistent behavior across locales.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Jean-Philippe Brule 2025-12-25 11:47:56 -05:00
parent 46e739eead
commit 599204d858

View File

@ -627,11 +627,11 @@ namespace Svrnty.CQRS.Grpc.Generators
{
if (prop.IsNullable)
{
return $"{indent}{prop.Name} = string.IsNullOrEmpty({source}) ? null : decimal.Parse({source}),";
return $"{indent}{prop.Name} = string.IsNullOrEmpty({source}) ? null : decimal.Parse({source}, System.Globalization.CultureInfo.InvariantCulture),";
}
else
{
return $"{indent}{prop.Name} = decimal.Parse({source}),";
return $"{indent}{prop.Name} = decimal.Parse({source}, System.Globalization.CultureInfo.InvariantCulture),";
}
}
@ -707,11 +707,11 @@ namespace Svrnty.CQRS.Grpc.Generators
{
if (prop.IsNullable)
{
return $"{indent}{prop.Name} = string.IsNullOrEmpty({source}) ? null : decimal.Parse({source}),";
return $"{indent}{prop.Name} = string.IsNullOrEmpty({source}) ? null : decimal.Parse({source}, System.Globalization.CultureInfo.InvariantCulture),";
}
else
{
return $"{indent}{prop.Name} = decimal.Parse({source}),";
return $"{indent}{prop.Name} = decimal.Parse({source}, System.Globalization.CultureInfo.InvariantCulture),";
}
}
@ -1990,16 +1990,16 @@ namespace Svrnty.CQRS.Grpc.Generators
if (prop.IsDecimal)
{
if (prop.IsNullable)
return $"string.IsNullOrEmpty({accessor}) ? null : decimal.Parse({accessor})";
return $"decimal.Parse({accessor})";
return $"string.IsNullOrEmpty({accessor}) ? null : decimal.Parse({accessor}, System.Globalization.CultureInfo.InvariantCulture)";
return $"decimal.Parse({accessor}, System.Globalization.CultureInfo.InvariantCulture)";
}
// Handle string → DateTime conversion (proto uses string for DateTime)
if (prop.IsDateTime)
{
if (prop.IsNullable)
return $"string.IsNullOrEmpty({accessor}) ? null : global::System.DateTime.Parse({accessor})";
return $"global::System.DateTime.Parse({accessor})";
return $"string.IsNullOrEmpty({accessor}) ? null : global::System.DateTime.Parse({accessor}, System.Globalization.CultureInfo.InvariantCulture)";
return $"global::System.DateTime.Parse({accessor}, System.Globalization.CultureInfo.InvariantCulture)";
}
// Handle proto enum → domain enum conversion