diff --git a/modules/feature-management/src/Volo.Abp.FeatureManagement.Application.Contracts/Volo/Abp/FeatureManagement/AbpFeatureManagementApplicationContractsModule.cs b/modules/feature-management/src/Volo.Abp.FeatureManagement.Application.Contracts/Volo/Abp/FeatureManagement/AbpFeatureManagementApplicationContractsModule.cs index daf82df6ad..cfbcf1c95e 100644 --- a/modules/feature-management/src/Volo.Abp.FeatureManagement.Application.Contracts/Volo/Abp/FeatureManagement/AbpFeatureManagementApplicationContractsModule.cs +++ b/modules/feature-management/src/Volo.Abp.FeatureManagement.Application.Contracts/Volo/Abp/FeatureManagement/AbpFeatureManagementApplicationContractsModule.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using Microsoft.Extensions.DependencyInjection; using Volo.Abp.Application; using Volo.Abp.Authorization; using Volo.Abp.FeatureManagement.JsonConverters; @@ -25,6 +26,12 @@ public class AbpFeatureManagementApplicationContractsModule : AbpModule options.FileSets.AddEmbedded(); }); + var contractsOptionsActions = context.Services.GetPreConfigureActions(); + Configure(options => + { + contractsOptionsActions.Configure(options); + }); + Configure(options => { options.Converters.Add(); @@ -32,7 +39,7 @@ public class AbpFeatureManagementApplicationContractsModule : AbpModule Configure(options => { - options.JsonSerializerOptions.Converters.AddIfNotContains(new StringValueTypeJsonConverter()); + options.JsonSerializerOptions.Converters.AddIfNotContains(new StringValueTypeJsonConverter(contractsOptionsActions.Configure())); }); } } diff --git a/modules/feature-management/src/Volo.Abp.FeatureManagement.Application.Contracts/Volo/Abp/FeatureManagement/AbpFeatureManagementApplicationContractsOptions.cs b/modules/feature-management/src/Volo.Abp.FeatureManagement.Application.Contracts/Volo/Abp/FeatureManagement/AbpFeatureManagementApplicationContractsOptions.cs new file mode 100644 index 0000000000..6c99bb648f --- /dev/null +++ b/modules/feature-management/src/Volo.Abp.FeatureManagement.Application.Contracts/Volo/Abp/FeatureManagement/AbpFeatureManagementApplicationContractsOptions.cs @@ -0,0 +1,21 @@ +using System.Collections.Generic; +using Volo.Abp.FeatureManagement.JsonConverters; +using Volo.Abp.Validation.StringValues; + +namespace Volo.Abp.FeatureManagement; + +public class AbpFeatureManagementApplicationContractsOptions +{ + public HashSet ValueValidatorFactory { get; } + + public AbpFeatureManagementApplicationContractsOptions() + { + ValueValidatorFactory = new HashSet + { + new ValueValidatorFactory("NULL"), + new ValueValidatorFactory("BOOLEAN"), + new ValueValidatorFactory("NUMERIC"), + new ValueValidatorFactory("STRING") + }; + } +} diff --git a/modules/feature-management/src/Volo.Abp.FeatureManagement.Application.Contracts/Volo/Abp/FeatureManagement/JsonConverters/IValueValidatorFactory.cs b/modules/feature-management/src/Volo.Abp.FeatureManagement.Application.Contracts/Volo/Abp/FeatureManagement/JsonConverters/IValueValidatorFactory.cs new file mode 100644 index 0000000000..7ce718a856 --- /dev/null +++ b/modules/feature-management/src/Volo.Abp.FeatureManagement.Application.Contracts/Volo/Abp/FeatureManagement/JsonConverters/IValueValidatorFactory.cs @@ -0,0 +1,10 @@ +using Volo.Abp.Validation.StringValues; + +namespace Volo.Abp.FeatureManagement.JsonConverters; + +public interface IValueValidatorFactory +{ + bool CanCreate(string name); + + IValueValidator Create(); +} diff --git a/modules/feature-management/src/Volo.Abp.FeatureManagement.Application.Contracts/Volo/Abp/FeatureManagement/JsonConverters/NewtonsoftStringValueTypeJsonConverter.cs b/modules/feature-management/src/Volo.Abp.FeatureManagement.Application.Contracts/Volo/Abp/FeatureManagement/JsonConverters/NewtonsoftStringValueTypeJsonConverter.cs index c85e48d0f3..aa9a913718 100644 --- a/modules/feature-management/src/Volo.Abp.FeatureManagement.Application.Contracts/Volo/Abp/FeatureManagement/JsonConverters/NewtonsoftStringValueTypeJsonConverter.cs +++ b/modules/feature-management/src/Volo.Abp.FeatureManagement.Application.Contracts/Volo/Abp/FeatureManagement/JsonConverters/NewtonsoftStringValueTypeJsonConverter.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.IO; using System.Linq; +using Microsoft.Extensions.Options; using Newtonsoft.Json; using Newtonsoft.Json.Linq; using Volo.Abp.DependencyInjection; @@ -13,6 +14,13 @@ public class NewtonsoftStringValueTypeJsonConverter : JsonConverter, ITransientD { public override bool CanWrite => false; + protected readonly AbpFeatureManagementApplicationContractsOptions Options; + + public NewtonsoftStringValueTypeJsonConverter(IOptions options) + { + Options = options.Value; + } + public override bool CanConvert(Type objectType) { return objectType == typeof(IStringValueType); @@ -77,13 +85,11 @@ public class NewtonsoftStringValueTypeJsonConverter : JsonConverter, ITransientD protected virtual IValueValidator CreateValueValidatorByName(JToken jObject, string name) { - return name switch + foreach (var factory in Options.ValueValidatorFactory.Where(factory => factory.CanCreate(name))) { - "NULL" => new AlwaysValidValueValidator(), - "BOOLEAN" => new BooleanValueValidator(), - "NUMERIC" => new NumericValueValidator(), - "STRING" => new StringValueValidator(), - _ => throw new ArgumentException($"{nameof(IValueValidator)} named {name} was not found!") - }; + return factory.Create(); + } + + throw new ArgumentException($"{nameof(IValueValidator)} named {name} was cannot be created!"); } } diff --git a/modules/feature-management/src/Volo.Abp.FeatureManagement.Application.Contracts/Volo/Abp/FeatureManagement/JsonConverters/StringValueTypeJsonConverter.cs b/modules/feature-management/src/Volo.Abp.FeatureManagement.Application.Contracts/Volo/Abp/FeatureManagement/JsonConverters/StringValueTypeJsonConverter.cs index a45fb1a409..ca91efd58a 100644 --- a/modules/feature-management/src/Volo.Abp.FeatureManagement.Application.Contracts/Volo/Abp/FeatureManagement/JsonConverters/StringValueTypeJsonConverter.cs +++ b/modules/feature-management/src/Volo.Abp.FeatureManagement.Application.Contracts/Volo/Abp/FeatureManagement/JsonConverters/StringValueTypeJsonConverter.cs @@ -12,6 +12,13 @@ public class StringValueTypeJsonConverter : JsonConverter private JsonSerializerOptions _writeJsonSerializerOptions; + protected readonly AbpFeatureManagementApplicationContractsOptions Options; + + public StringValueTypeJsonConverter(AbpFeatureManagementApplicationContractsOptions options) + { + Options = options; + } + public override IStringValueType Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { var rootElement = JsonDocument.ParseValue(ref reader).RootElement; @@ -21,7 +28,8 @@ public class StringValueTypeJsonConverter : JsonConverter { var name = nameJsonProperty.Value.GetString(); - _readJsonSerializerOptions ??= JsonSerializerOptionsHelper.Create(options, this, new ValueValidatorJsonConverter(), new SelectionStringValueItemSourceJsonConverter()); + _readJsonSerializerOptions ??= JsonSerializerOptionsHelper.Create(options, this, new ValueValidatorJsonConverter(Options), + new SelectionStringValueItemSourceJsonConverter()); return name switch { diff --git a/modules/feature-management/src/Volo.Abp.FeatureManagement.Application.Contracts/Volo/Abp/FeatureManagement/JsonConverters/ValueValidatorFactory.cs b/modules/feature-management/src/Volo.Abp.FeatureManagement.Application.Contracts/Volo/Abp/FeatureManagement/JsonConverters/ValueValidatorFactory.cs new file mode 100644 index 0000000000..501c450411 --- /dev/null +++ b/modules/feature-management/src/Volo.Abp.FeatureManagement.Application.Contracts/Volo/Abp/FeatureManagement/JsonConverters/ValueValidatorFactory.cs @@ -0,0 +1,24 @@ +using Volo.Abp.Validation.StringValues; + +namespace Volo.Abp.FeatureManagement.JsonConverters; + +public class ValueValidatorFactory : IValueValidatorFactory + where TValueValidator : IValueValidator, new() +{ + protected readonly string Name; + + public ValueValidatorFactory(string name) + { + Name = name; + } + + public bool CanCreate(string name) + { + return Name == name; + } + + public IValueValidator Create() + { + return new TValueValidator() as IValueValidator; + } +} diff --git a/modules/feature-management/src/Volo.Abp.FeatureManagement.Application.Contracts/Volo/Abp/FeatureManagement/JsonConverters/ValueValidatorJsonConverter.cs b/modules/feature-management/src/Volo.Abp.FeatureManagement.Application.Contracts/Volo/Abp/FeatureManagement/JsonConverters/ValueValidatorJsonConverter.cs index 8d1a60056e..69f954f4ee 100644 --- a/modules/feature-management/src/Volo.Abp.FeatureManagement.Application.Contracts/Volo/Abp/FeatureManagement/JsonConverters/ValueValidatorJsonConverter.cs +++ b/modules/feature-management/src/Volo.Abp.FeatureManagement.Application.Contracts/Volo/Abp/FeatureManagement/JsonConverters/ValueValidatorJsonConverter.cs @@ -14,6 +14,13 @@ public class ValueValidatorJsonConverter : JsonConverter private JsonSerializerOptions _writeJsonSerializerOptions; + protected readonly AbpFeatureManagementApplicationContractsOptions Options; + + public ValueValidatorJsonConverter(AbpFeatureManagementApplicationContractsOptions options) + { + Options = options; + } + public override IValueValidator Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { var rootElement = JsonDocument.ParseValue(ref reader).RootElement; @@ -51,13 +58,11 @@ public class ValueValidatorJsonConverter : JsonConverter protected virtual IValueValidator CreateValueValidatorByName(string name) { - return name switch + foreach (var factory in Options.ValueValidatorFactory.Where(factory => factory.CanCreate(name))) { - "NULL" => new AlwaysValidValueValidator(), - "BOOLEAN" => new BooleanValueValidator(), - "NUMERIC" => new NumericValueValidator(), - "STRING" => new StringValueValidator(), - _ => throw new ArgumentException($"{nameof(IValueValidator)} named {name} was not found!") - }; + return factory.Create(); + } + + throw new ArgumentException($"{nameof(IValueValidator)} named {name} was cannot be created!"); } } diff --git a/modules/feature-management/src/Volo.Abp.FeatureManagement.HttpApi/Volo/Abp/FeatureManagement/AbpFeatureManagementHttpApiModule.cs b/modules/feature-management/src/Volo.Abp.FeatureManagement.HttpApi/Volo/Abp/FeatureManagement/AbpFeatureManagementHttpApiModule.cs index 1963c60fd5..2a0b33d818 100644 --- a/modules/feature-management/src/Volo.Abp.FeatureManagement.HttpApi/Volo/Abp/FeatureManagement/AbpFeatureManagementHttpApiModule.cs +++ b/modules/feature-management/src/Volo.Abp.FeatureManagement.HttpApi/Volo/Abp/FeatureManagement/AbpFeatureManagementHttpApiModule.cs @@ -32,9 +32,10 @@ public class AbpFeatureManagementHttpApiModule : AbpModule .AddBaseTypes(typeof(AbpUiResource)); }); + var contractsOptions = context.Services.ExecutePreConfiguredActions(); Configure(options => { - options.JsonSerializerOptions.Converters.AddIfNotContains(new StringValueTypeJsonConverter()); + options.JsonSerializerOptions.Converters.AddIfNotContains(new StringValueTypeJsonConverter(contractsOptions)); }); } } diff --git a/modules/feature-management/test/Volo.Abp.FeatureManagement.Application.Tests/Volo/Abp/FeatureManagement/NewtonsoftStringValueJsonConverter_Tests.cs b/modules/feature-management/test/Volo.Abp.FeatureManagement.Application.Tests/Volo/Abp/FeatureManagement/NewtonsoftStringValueJsonConverter_Tests.cs index a778a8717b..09f3c2266d 100644 --- a/modules/feature-management/test/Volo.Abp.FeatureManagement.Application.Tests/Volo/Abp/FeatureManagement/NewtonsoftStringValueJsonConverter_Tests.cs +++ b/modules/feature-management/test/Volo.Abp.FeatureManagement.Application.Tests/Volo/Abp/FeatureManagement/NewtonsoftStringValueJsonConverter_Tests.cs @@ -9,7 +9,7 @@ public class NewtonsoftStringValueJsonConverter_Tests : StringValueJsonConverter { services.PreConfigure(options => { - options.UseHybridSerializer = true; + options.UseHybridSerializer = false; }); } } diff --git a/modules/feature-management/test/Volo.Abp.FeatureManagement.Application.Tests/Volo/Abp/FeatureManagement/StringValueJsonConverter_Tests.cs b/modules/feature-management/test/Volo.Abp.FeatureManagement.Application.Tests/Volo/Abp/FeatureManagement/StringValueJsonConverter_Tests.cs index 137a8d0c13..28b8e55052 100644 --- a/modules/feature-management/test/Volo.Abp.FeatureManagement.Application.Tests/Volo/Abp/FeatureManagement/StringValueJsonConverter_Tests.cs +++ b/modules/feature-management/test/Volo.Abp.FeatureManagement.Application.Tests/Volo/Abp/FeatureManagement/StringValueJsonConverter_Tests.cs @@ -1,6 +1,8 @@ using System; using System.Collections.Generic; +using Microsoft.Extensions.DependencyInjection; using Shouldly; +using Volo.Abp.FeatureManagement.JsonConverters; using Volo.Abp.Json; using Volo.Abp.Validation.StringValues; using Xunit; @@ -16,6 +18,16 @@ public abstract class StringValueJsonConverter_Tests : FeatureManagementApplicat _jsonSerializer = GetRequiredService(); } + protected override void BeforeAddApplication(IServiceCollection services) + { + services.PreConfigure(options => + { + options.ValueValidatorFactory.Add(new ValueValidatorFactory("URL")); + }); + + base.BeforeAddApplication(services); + } + [Fact] public void Should_Serialize_And_Deserialize() { @@ -67,6 +79,13 @@ public abstract class StringValueJsonConverter_Tests : FeatureManagementApplicat Name = "FeatureName", Key = "FeatureKey" } + }, + new FeatureDto + { + ValueType = new FreeTextStringValueType + { + Validator = new UrlValueValidator("https") + } } } } @@ -95,5 +114,9 @@ public abstract class StringValueJsonConverter_Tests : FeatureManagementApplicat featureListDto2.Groups[0].Features[3].Provider.Name.ShouldBe("FeatureName"); featureListDto2.Groups[0].Features[3].Provider.Key.ShouldBe("FeatureKey"); + + featureListDto2.Groups[0].Features[4].ValueType.ShouldBeOfType(); + featureListDto2.Groups[0].Features[4].ValueType.Validator.ShouldBeOfType(); + featureListDto2.Groups[0].Features[4].ValueType.Validator.As().Scheme.ShouldBe("https"); } } diff --git a/modules/feature-management/test/Volo.Abp.FeatureManagement.Application.Tests/Volo/Abp/FeatureManagement/SystemTextJsonStringValueJsonConverter_Tests.cs b/modules/feature-management/test/Volo.Abp.FeatureManagement.Application.Tests/Volo/Abp/FeatureManagement/SystemTextJsonStringValueJsonConverter_Tests.cs index b4791c46cd..968055c09f 100644 --- a/modules/feature-management/test/Volo.Abp.FeatureManagement.Application.Tests/Volo/Abp/FeatureManagement/SystemTextJsonStringValueJsonConverter_Tests.cs +++ b/modules/feature-management/test/Volo.Abp.FeatureManagement.Application.Tests/Volo/Abp/FeatureManagement/SystemTextJsonStringValueJsonConverter_Tests.cs @@ -9,7 +9,7 @@ public class SystemTextJsonStringValueJsonConverter_Tests : StringValueJsonConve { services.PreConfigure(options => { - options.UseHybridSerializer = false; + options.UseHybridSerializer = true; }); } } diff --git a/modules/feature-management/test/Volo.Abp.FeatureManagement.Application.Tests/Volo/Abp/FeatureManagement/UrlValueValidator.cs b/modules/feature-management/test/Volo.Abp.FeatureManagement.Application.Tests/Volo/Abp/FeatureManagement/UrlValueValidator.cs new file mode 100644 index 0000000000..6b29edcb2a --- /dev/null +++ b/modules/feature-management/test/Volo.Abp.FeatureManagement.Application.Tests/Volo/Abp/FeatureManagement/UrlValueValidator.cs @@ -0,0 +1,30 @@ +using System; +using Volo.Abp.Validation.StringValues; + +namespace Volo.Abp.FeatureManagement; + +[Serializable] +[ValueValidator("URL")] +public class UrlValueValidator : ValueValidatorBase +{ + public string Scheme { + get => this["Scheme"].ToString(); + set => this["Scheme"] = value; + } + + public UrlValueValidator() + { + + } + + public UrlValueValidator(string scheme) + { + Scheme = scheme; + } + + public override bool IsValid(object value) + { + var s = value.ToString(); + return s != null && s.StartsWith(Scheme); + } +}