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 63b3538c3a..87b94774e7 100644 --- a/framework/src/Volo.Abp.Core/Volo/Abp/Reflection/TypeHelper.cs +++ b/framework/src/Volo.Abp.Core/Volo/Abp/Reflection/TypeHelper.cs @@ -10,6 +10,30 @@ namespace Volo.Abp.Reflection { public static class TypeHelper { + private static readonly HashSet NonNullablePrimitiveTypes = new HashSet + { + typeof(byte), + typeof(short), + typeof(int), + typeof(long), + typeof(sbyte), + typeof(ushort), + typeof(uint), + typeof(ulong), + typeof(bool), + typeof(float), + typeof(decimal), + typeof(DateTime), + typeof(DateTimeOffset), + typeof(TimeSpan), + typeof(Guid) + }; + + public static bool IsNonNullablePrimitiveType(Type type) + { + return NonNullablePrimitiveTypes.Contains(type); + } + public static bool IsFunc(object obj) { if (obj == null) diff --git a/framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/ExtensionPropertyHelper.cs b/framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/ExtensionPropertyHelper.cs new file mode 100644 index 0000000000..507f67997a --- /dev/null +++ b/framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/ExtensionPropertyHelper.cs @@ -0,0 +1,23 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using Volo.Abp.Reflection; + +namespace Volo.Abp.ObjectExtending +{ + public static class ExtensionPropertyHelper + { + public static IEnumerable GetDefaultAttributes(Type type) + { + if (TypeHelper.IsNonNullablePrimitiveType(type) || type.IsEnum) + { + yield return new RequiredAttribute(); + } + + if (type.IsEnum) + { + yield return new EnumDataTypeAttribute(type); + } + } + } +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/Modularity/ExtensionPropertyConfiguration.cs b/framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/Modularity/ExtensionPropertyConfiguration.cs index 0ff3941f4e..47882fdf93 100644 --- a/framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/Modularity/ExtensionPropertyConfiguration.cs +++ b/framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/Modularity/ExtensionPropertyConfiguration.cs @@ -61,6 +61,8 @@ namespace Volo.Abp.ObjectExtending.Modularity Entity = new ExtensionPropertyEntityConfiguration(); UI = new ExtensionPropertyUiConfiguration(); Api = new ExtensionPropertyApiConfiguration(); + + Attributes.AddRange(ExtensionPropertyHelper.GetDefaultAttributes(Type)); } } } \ No newline at end of file diff --git a/framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/Modularity/ModuleExtensionConfigurationHelper.cs b/framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/Modularity/ModuleExtensionConfigurationHelper.cs index 1f1edd757e..d819918ac5 100644 --- a/framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/Modularity/ModuleExtensionConfigurationHelper.cs +++ b/framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/Modularity/ModuleExtensionConfigurationHelper.cs @@ -148,6 +148,7 @@ namespace Volo.Abp.ObjectExtending.Modularity propertyConfig.Name, property => { + property.Attributes.Clear(); property.Attributes.AddRange(propertyConfig.Attributes); property.DisplayName = propertyConfig.DisplayName; property.Validators.AddRange(propertyConfig.Validators); diff --git a/framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/ObjectExtensionPropertyInfo.cs b/framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/ObjectExtensionPropertyInfo.cs index 5d55325477..e89598e6d2 100644 --- a/framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/ObjectExtensionPropertyInfo.cs +++ b/framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/ObjectExtensionPropertyInfo.cs @@ -2,7 +2,6 @@ using System.Collections.Generic; using System.ComponentModel.DataAnnotations; using JetBrains.Annotations; -using Microsoft.Extensions.Localization; using Volo.Abp.Localization; namespace Volo.Abp.ObjectExtending @@ -61,6 +60,8 @@ namespace Volo.Abp.ObjectExtending ValidationAttributes = new List(); Attributes = new List(); Validators = new List>(); + + Attributes.AddRange(ExtensionPropertyHelper.GetDefaultAttributes(Type)); } } } diff --git a/framework/test/Volo.Abp.Core.Tests/Volo/Abp/Reflection/TypeHelper_Tests.cs b/framework/test/Volo.Abp.Core.Tests/Volo/Abp/Reflection/TypeHelper_Tests.cs index 02056aab20..978bf9de54 100644 --- a/framework/test/Volo.Abp.Core.Tests/Volo/Abp/Reflection/TypeHelper_Tests.cs +++ b/framework/test/Volo.Abp.Core.Tests/Volo/Abp/Reflection/TypeHelper_Tests.cs @@ -7,6 +7,13 @@ namespace Volo.Abp.Reflection { public class TypeHelper_Tests { + [Fact] + public void IsNonNullablePrimitiveType() + { + TypeHelper.IsNonNullablePrimitiveType(typeof(int)).ShouldBeTrue(); + TypeHelper.IsNonNullablePrimitiveType(typeof(string)).ShouldBeFalse(); + } + [Fact] public void Should_Generic_Type_From_Nullable() { diff --git a/framework/test/Volo.Abp.ObjectExtending.Tests/Volo/Abp/ObjectExtending/ObjectExtensionManager_Tests.cs b/framework/test/Volo.Abp.ObjectExtending.Tests/Volo/Abp/ObjectExtending/ObjectExtensionManager_Tests.cs index 857e2fd155..cb5b308c64 100644 --- a/framework/test/Volo.Abp.ObjectExtending.Tests/Volo/Abp/ObjectExtending/ObjectExtensionManager_Tests.cs +++ b/framework/test/Volo.Abp.ObjectExtending.Tests/Volo/Abp/ObjectExtending/ObjectExtensionManager_Tests.cs @@ -1,4 +1,5 @@ -using System.Linq; +using System.ComponentModel.DataAnnotations; +using System.Linq; using Shouldly; using Xunit; @@ -22,7 +23,7 @@ namespace Volo.Abp.ObjectExtending var objectExtension = _objectExtensionManager.GetOrNull(); objectExtension.ShouldNotBeNull(); - + var properties = objectExtension.GetProperties(); properties.Count.ShouldBe(1); properties.FirstOrDefault(p => p.Name == "TestProp").ShouldNotBeNull(); @@ -55,9 +56,78 @@ namespace Volo.Abp.ObjectExtending property.Configuration["TestConfig2"].ShouldBe("TestConfig2-Value"); } + [Fact] + public void Should_Automatically_Add_RequiredAttribute_To_Non_Nullable_Types_And_Enums() + { + _objectExtensionManager + .AddOrUpdateProperty("IntProp") + .AddOrUpdateProperty("BoolProp") + .AddOrUpdateProperty("NullableIntProp") + .AddOrUpdateProperty("StringProp") + .AddOrUpdateProperty("EnumProp"); + + _objectExtensionManager + .GetPropertyOrNull("IntProp") + .Attributes + .ShouldContain(x => x is RequiredAttribute); + + _objectExtensionManager + .GetPropertyOrNull("BoolProp") + .Attributes + .ShouldContain(x => x is RequiredAttribute); + + _objectExtensionManager + .GetPropertyOrNull("EnumProp") + .Attributes + .ShouldContain(x => x is RequiredAttribute); + + _objectExtensionManager + .GetPropertyOrNull("NullableIntProp") + .Attributes + .ShouldNotContain(x => x is RequiredAttribute); + + _objectExtensionManager + .GetPropertyOrNull("StringProp") + .Attributes + .ShouldNotContain(x => x is RequiredAttribute); + } + + [Fact] + public void Should_Automatically_Add_EnumDataTypeAttribute_For_Enums() + { + _objectExtensionManager + .AddOrUpdateProperty("EnumProp"); + + _objectExtensionManager + .GetPropertyOrNull("EnumProp") + .Attributes + .ShouldContain(x => x is EnumDataTypeAttribute); + } + + [Fact] + public void Should_Be_Able_To_Clear_Auto_Added_Attributes() + { + _objectExtensionManager + .AddOrUpdateProperty("IntProp", property => + { + property.Attributes.Clear(); + }); + + _objectExtensionManager + .GetPropertyOrNull("IntProp") + .Attributes + .ShouldNotContain(x => x is RequiredAttribute); + } + private class MyExtensibleObject : ExtensibleObject { } + + private enum MyTestEnum + { + EnumValue1, + EnumValue2, + } } }