From 0100b5ad04ef6ae99338245df7b31a04fd1c5675 Mon Sep 17 00:00:00 2001 From: badhitman <10000335+badhitman@users.noreply.github.com> Date: Wed, 28 Aug 2019 11:11:00 +0300 Subject: [PATCH] init --- ...tNetCore2BinderFloatingDecimalModel.csproj | 11 ++ CustomDoubleModelBinderProvider.cs | 33 ++++++ CustomFloatingModelBinder.cs | 104 ++++++++++++++++++ README.md | 14 +++ 4 files changed, 162 insertions(+) create mode 100644 AspDotNetCore2BinderFloatingDecimalModel.csproj create mode 100644 CustomDoubleModelBinderProvider.cs create mode 100644 CustomFloatingModelBinder.cs diff --git a/AspDotNetCore2BinderFloatingDecimalModel.csproj b/AspDotNetCore2BinderFloatingDecimalModel.csproj new file mode 100644 index 0000000..1271dd0 --- /dev/null +++ b/AspDotNetCore2BinderFloatingDecimalModel.csproj @@ -0,0 +1,11 @@ + + + + netcoreapp2.2 + + + + + + + diff --git a/CustomDoubleModelBinderProvider.cs b/CustomDoubleModelBinderProvider.cs new file mode 100644 index 0000000..64ac9fa --- /dev/null +++ b/CustomDoubleModelBinderProvider.cs @@ -0,0 +1,33 @@ +//////////////////////////////////////////////// +// © https://github.com/badhitman - @fakegov +//////////////////////////////////////////////// +using Microsoft.AspNetCore.Mvc.ModelBinding; +using Microsoft.AspNetCore.Mvc.ModelBinding.Binders; +using Microsoft.Extensions.Logging; + +namespace AspDotNetCore2BinderFloatingDecimalModel +{ + public class CustomDecimalModelBinderProvider : IModelBinderProvider + { + private IModelBinder binder; + + public IModelBinder GetBinder(ModelBinderProviderContext context) + { + ILoggerFactory logger = context.Services.GetService(typeof(ILoggerFactory)) as ILoggerFactory; + + if (context.Metadata.ModelType == typeof(double)) + binder = new CustomFloatingModelBinder(new SimpleTypeModelBinder(typeof(double), logger)); + + else if (context.Metadata.ModelType == typeof(float)) + binder = new CustomFloatingModelBinder(new SimpleTypeModelBinder(typeof(float), logger)); + + else if (context.Metadata.ModelType == typeof(decimal)) + binder = new CustomFloatingModelBinder(new SimpleTypeModelBinder(typeof(decimal), logger)); + + else + return null; + + return binder; + } + } +} diff --git a/CustomFloatingModelBinder.cs b/CustomFloatingModelBinder.cs new file mode 100644 index 0000000..8b7c32d --- /dev/null +++ b/CustomFloatingModelBinder.cs @@ -0,0 +1,104 @@ +//////////////////////////////////////////////// +// © https://github.com/badhitman - @fakegov +//////////////////////////////////////////////// +using Microsoft.AspNetCore.Mvc.ModelBinding; +using System; +using System.Globalization; +using System.Text.RegularExpressions; +using System.Threading.Tasks; + +namespace AspDotNetCore2BinderFloatingDecimalModel +{ + public class CustomFloatingModelBinder : IModelBinder + { + private readonly IModelBinder FallbackModelBinder; + private string FieldName; + private string FieldValueAsString; + private string FieldValueAsNormalString; + private ValueProviderResult PartValues; + + protected readonly Regex FloatPattern = new Regex(@"^(-?)[0-9]*(?:[.,][0-9]*)?$", RegexOptions.Compiled); + protected readonly Regex FloatSeparator = new Regex(@"[.,]", RegexOptions.Compiled); + + public CustomFloatingModelBinder(IModelBinder fallback_model_binder) + { + this.FallbackModelBinder = fallback_model_binder; + } + + public Task BindModelAsync(ModelBindingContext model_binding_context) + { + if (model_binding_context == null) + throw new ArgumentNullException(nameof(model_binding_context)); + + FieldName = model_binding_context.FieldName; + + PartValues = model_binding_context.ValueProvider.GetValue(FieldName); + + if (PartValues == ValueProviderResult.None) + return FallbackModelBinder.BindModelAsync(model_binding_context); + + FieldValueAsString = FieldValueAsNormalString = PartValues.FirstValue; + + //////////////////////////////////////////////////// + // если строка содержит десятичный/дробный разделитель -> строка дополняется нулями с обоих сторон. + // Таким образом исключаем точки в начале или в конце строки: + // ".5" -> "0.50" + // "5." -> "05.0" + if (FloatSeparator.IsMatch(FieldValueAsNormalString)) + FieldValueAsNormalString = "0" + FieldValueAsNormalString + "0"; + + //////////////////////////////////////////////////// + // заменим дробный разделитель на текущий системный + FieldValueAsNormalString = FloatSeparator.Replace(FieldValueAsNormalString, CultureInfo.CurrentCulture.NumberFormat.NumberDecimalSeparator); + + //////////////////////////////////////////////////// + // если не корректная строка -> передаём привязку системному привязчику + if (!FloatPattern.IsMatch(FieldValueAsNormalString)) + return FallbackModelBinder.BindModelAsync(model_binding_context); + + if (model_binding_context.ModelMetadata.ModelType == typeof(double)) + model_binding_context.Result = ModelBindingResult.Success(GetDoubleFromString); + else if (model_binding_context.ModelMetadata.ModelType == typeof(float)) + model_binding_context.Result = ModelBindingResult.Success(GetFloatFromString); + else if (model_binding_context.ModelMetadata.ModelType == typeof(decimal)) + model_binding_context.Result = ModelBindingResult.Success(GetDecimalFromString); + else + return FallbackModelBinder.BindModelAsync(model_binding_context); + + return Task.CompletedTask; + } + + public double GetDoubleFromString + { + get + { + if (!double.TryParse(FieldValueAsNormalString, NumberStyles.AllowDecimalPoint, CultureInfo.CurrentCulture, out double ret_val)) + return 0; + + return ret_val; + } + } + + public decimal GetDecimalFromString + { + get + { + if (!decimal.TryParse(FieldValueAsNormalString, NumberStyles.AllowDecimalPoint, CultureInfo.CurrentCulture, out decimal ret_val)) + return 0; + + return ret_val; + } + } + + public float GetFloatFromString + { + get + { + if (!float.TryParse(FieldValueAsNormalString, NumberStyles.AllowDecimalPoint, CultureInfo.CurrentCulture, out float ret_val)) + return 0; + + return ret_val; + } + } + } +} diff --git a/README.md b/README.md index cb3f3d4..a52b3a9 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,16 @@ # ASP.NET Core 2.2 BinderFloatingDecimalModel Привязчик модели для числовых значений double, float и decimal в ASP.NET Core 2.2 + +Использование: +```C# +using AspDotNetCore2BinderFloatingDecimalModel; +// ... +public void ConfigureServices(IServiceCollection services) +{ + // ... + services.AddMvc(opts => + { + opts.ModelBinderProviders.Insert(0, new CustomDecimalModelBinderProvider()); + }).SetCompatibilityVersion(CompatibilityVersion.Version_2_2); +} +``` \ No newline at end of file