profileShare

rasmusjy / splitapp-backend-microservices

Read-only snapshot

No repository description.

main default branch 501 files Expires Sep 13, 2026, 9:06 AM
InvariantDecimalModelBinderProvider.cs 1,733 bytes
1 using System.Globalization;
2 using Microsoft.AspNetCore.Mvc.ModelBinding;
3
4 namespace SplitApp.WebApp.Hosting;
5
6 /// <summary>
7 /// Ensures decimal values from HTML number inputs (which always send dot-separated values)
8 /// bind correctly regardless of the server's request culture (e.g. et-EE uses comma).
9 /// </summary>
10 public class InvariantDecimalModelBinderProvider : IModelBinderProvider
11 {
12 public IModelBinder? GetBinder(ModelBinderProviderContext context)
13 {
14 if (context.Metadata.ModelType == typeof(decimal) || context.Metadata.ModelType == typeof(decimal?))
15 {
16 return new InvariantDecimalModelBinder();
17 }
18
19 return null;
20 }
21 }
22
23 public class InvariantDecimalModelBinder : IModelBinder
24 {
25 public Task BindModelAsync(ModelBindingContext bindingContext)
26 {
27 var valueResult = bindingContext.ValueProvider.GetValue(bindingContext.ModelName);
28 if (valueResult == ValueProviderResult.None)
29 return Task.CompletedTask;
30
31 var value = valueResult.FirstValue;
32 if (string.IsNullOrWhiteSpace(value))
33 {
34 if (bindingContext.ModelType == typeof(decimal?))
35 {
36 bindingContext.Result = ModelBindingResult.Success(null);
37 }
38
39 return Task.CompletedTask;
40 }
41
42 value = value.Replace(',', '.');
43
44 if (decimal.TryParse(value, NumberStyles.Any, CultureInfo.InvariantCulture, out var result))
45 {
46 bindingContext.Result = ModelBindingResult.Success(result);
47 }
48 else
49 {
50 bindingContext.ModelState.TryAddModelError(bindingContext.ModelName, "Invalid number format.");
51 }
52
53 return Task.CompletedTask;
54 }
55 }
56