From c17868e5acef0ce3135e22d6ce07c90e5c25face Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Tue, 19 May 2020 05:17:15 +0300 Subject: [PATCH] Handle floating numbers on extension properties. --- .../Extensions/TagHelperExtensions.cs | 20 +++++-- .../Form/AbpInputTagHelperService.cs | 40 +++++++++++-- ...UiObjectExtensionPropertyInfoExtensions.cs | 17 ++++++ ...PropertiesDictionaryModelBinderProvider.cs | 1 - .../AbpExtraPropertyModelBinder.cs | 6 +- .../Volo/Abp/Reflection/TypeHelper.cs | 56 +++++++++++++++++-- 6 files changed, 122 insertions(+), 18 deletions(-) diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Extensions/TagHelperExtensions.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Extensions/TagHelperExtensions.cs index af961a2bf6..761b72ec99 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Extensions/TagHelperExtensions.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Extensions/TagHelperExtensions.cs @@ -7,14 +7,26 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Extensions { public static class TagHelperExtensions { - public static async Task ProcessAndGetOutputAsync(this TagHelper tagHelper, TagHelperAttributeList attributeList, TagHelperContext context, string tagName = "div", TagMode tagMode = TagMode.SelfClosing) + public static async Task ProcessAndGetOutputAsync( + this TagHelper tagHelper, + TagHelperAttributeList attributeList, + TagHelperContext context, + string tagName = "div", + TagMode tagMode = TagMode.SelfClosing) { - var innerOutput = new TagHelperOutput(tagName, attributeList, (useCachedResult, encoder) => Task.Run(() => new DefaultTagHelperContent())) + var innerOutput = new TagHelperOutput( + tagName, + attributeList, + (useCachedResult, encoder) => Task.Run(() => new DefaultTagHelperContent())) { TagMode = tagMode }; - - var innerContext = new TagHelperContext(attributeList, context.Items, Guid.NewGuid().ToString()); + + var innerContext = new TagHelperContext( + attributeList, + context.Items, + Guid.NewGuid().ToString() + ); tagHelper.Init(context); diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpInputTagHelperService.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpInputTagHelperService.cs index b03b0c8b69..932c6d5864 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpInputTagHelperService.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpInputTagHelperService.cs @@ -115,22 +115,40 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form }; } - return new InputTagHelper(_generator) + var inputTagHelper = new InputTagHelper(_generator) { For = TagHelper.AspFor, InputTypeName = TagHelper.InputTypeName, - ViewContext = TagHelper.ViewContext, - Format = TagHelper.Format, - Name = TagHelper.Name, - Value = TagHelper.Value + ViewContext = TagHelper.ViewContext }; + + if (!TagHelper.Format.IsNullOrEmpty()) + { + inputTagHelper.Format = TagHelper.Format; + } + + if (!TagHelper.Name.IsNullOrEmpty()) + { + inputTagHelper.Name = TagHelper.Name; + } + + if (!TagHelper.Value.IsNullOrEmpty()) + { + inputTagHelper.Value = TagHelper.Value; + } + + return inputTagHelper; } protected virtual async Task<(TagHelperOutput, bool)> GetInputTagHelperOutputAsync(TagHelperContext context, TagHelperOutput output) { var tagHelper = GetInputTagHelper(context, output); - var inputTagHelperOutput = await tagHelper.ProcessAndGetOutputAsync(GetInputAttributes(context, output), context, "input"); + var inputTagHelperOutput = await tagHelper.ProcessAndGetOutputAsync( + GetInputAttributes(context, output), + context, + "input" + ); ConvertToTextAreaIfTextArea(inputTagHelperOutput); AddDisabledAttribute(inputTagHelperOutput); @@ -349,6 +367,16 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form attrList.Add("type", TagHelper.InputTypeName); } + if (!TagHelper.Name.IsNullOrEmpty() && !attrList.ContainsName("name")) + { + attrList.Add("name", TagHelper.Name); + } + + if (!TagHelper.Value.IsNullOrEmpty() && !attrList.ContainsName("value")) + { + attrList.Add("value", TagHelper.Value); + } + return attrList; } diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI/Volo/Abp/ObjectExtending/MvcUiObjectExtensionPropertyInfoExtensions.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI/Volo/Abp/ObjectExtending/MvcUiObjectExtensionPropertyInfoExtensions.cs index 1ebe486068..7aea3cf9f2 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI/Volo/Abp/ObjectExtending/MvcUiObjectExtensionPropertyInfoExtensions.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI/Volo/Abp/ObjectExtending/MvcUiObjectExtensionPropertyInfoExtensions.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.ComponentModel.DataAnnotations; using Microsoft.AspNetCore.Mvc; +using Volo.Abp.Reflection; namespace Volo.Abp.ObjectExtending { @@ -49,6 +50,22 @@ namespace Volo.Abp.ObjectExtending return null; } + public static string GetInputValueOrNull(this IBasicObjectExtensionPropertyInfo property, object value) + { + if (value == null) + { + return null; + } + + if (TypeHelper.IsFloatingType(property.Type)) + { + return value.ToString()?.Replace(',', '.'); + } + + /* Let the ASP.NET Core handle it! */ + return null; + } + public static string GetInputType(this ObjectExtensionPropertyInfo propertyInfo) { foreach (var attribute in propertyInfo.Attributes) diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ModelBinding/AbpExtraPropertiesDictionaryModelBinderProvider.cs b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ModelBinding/AbpExtraPropertiesDictionaryModelBinderProvider.cs index 3ed1eda3a1..812ca30f06 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ModelBinding/AbpExtraPropertiesDictionaryModelBinderProvider.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ModelBinding/AbpExtraPropertiesDictionaryModelBinderProvider.cs @@ -1,6 +1,5 @@ using System; using System.Collections.Generic; -using System.Text; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.ModelBinding; using Microsoft.AspNetCore.Mvc.ModelBinding.Binders; diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ModelBinding/AbpExtraPropertyModelBinder.cs b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ModelBinding/AbpExtraPropertyModelBinder.cs index c94ad08e74..d09da73a59 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ModelBinding/AbpExtraPropertyModelBinder.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ModelBinding/AbpExtraPropertyModelBinder.cs @@ -1,5 +1,4 @@ using System; -using System.ComponentModel; using System.Threading.Tasks; using Microsoft.AspNetCore.Mvc.ModelBinding; using Volo.Abp.ObjectExtending; @@ -61,7 +60,10 @@ namespace Volo.Abp.AspNetCore.Mvc.ModelBinding return value; } - return TypeHelper.ConvertFromString(propertyInfo.Type, value); + return TypeHelper.ConvertFromString( + propertyInfo.Type, + value + ); } } } \ No newline at end of file diff --git a/framework/src/Volo.Abp.Core/Volo/Abp/Reflection/TypeHelper.cs b/framework/src/Volo.Abp.Core/Volo/Abp/Reflection/TypeHelper.cs index 192043a800..83182fc965 100644 --- a/framework/src/Volo.Abp.Core/Volo/Abp/Reflection/TypeHelper.cs +++ b/framework/src/Volo.Abp.Core/Volo/Abp/Reflection/TypeHelper.cs @@ -2,14 +2,23 @@ using System.Collections; using System.Collections.Generic; using System.ComponentModel; +using System.Globalization; using System.Linq; using System.Reflection; using JetBrains.Annotations; +using Volo.Abp.Localization; namespace Volo.Abp.Reflection { public static class TypeHelper { + private static readonly HashSet FloatingTypes = new HashSet + { + typeof(float), + typeof(double), + typeof(decimal) + }; + private static readonly HashSet NonNullablePrimitiveTypes = new HashSet { typeof(byte), @@ -40,7 +49,7 @@ namespace Volo.Abp.Reflection { return false; } - + var type = obj.GetType(); if (!type.GetTypeInfo().IsGenericType) { @@ -169,7 +178,7 @@ namespace Volo.Abp.Reflection { return Activator.CreateInstance(type); } - + return null; } @@ -297,9 +306,39 @@ namespace Volo.Abp.Reflection public static object ConvertFromString(Type targetType, string value) { - return TypeDescriptor - .GetConverter(targetType) - .ConvertFromString(value); + if (value == null) + { + return null; + } + + var converter = TypeDescriptor.GetConverter(targetType); + + if (IsFloatingType(targetType)) + { + using (CultureHelper.Use(CultureInfo.InvariantCulture)) + { + return converter.ConvertFromString(value.Replace(',', '.')); + } + } + + return converter.ConvertFromString(value); + } + + public static bool IsFloatingType(Type type, bool includeNullable = true) + { + if (FloatingTypes.Contains(type)) + { + return true; + } + + if (includeNullable && + IsNullable(type) && + FloatingTypes.Contains(type.GenericTypeArguments[0])) + { + return true; + } + + return false; } public static object ConvertFrom(object value) @@ -313,5 +352,12 @@ namespace Volo.Abp.Reflection .GetConverter(targetType) .ConvertFrom(value); } + + public static Type StripNullable(Type type) + { + return IsNullable(type) + ? type.GenericTypeArguments[0] + : type; + } } }