diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ModelBinding/Metadata/AbpModelMetadataProvider.cs b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ModelBinding/Metadata/AbpModelMetadataProvider.cs index b77354aab2..94a08a0507 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ModelBinding/Metadata/AbpModelMetadataProvider.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ModelBinding/Metadata/AbpModelMetadataProvider.cs @@ -1,11 +1,11 @@ using System.ComponentModel.DataAnnotations; using System.Linq; -using System.Reflection; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.ModelBinding; using Microsoft.AspNetCore.Mvc.ModelBinding.Metadata; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Options; +using Volo.Abp.AspNetCore.Mvc.Validation; using Volo.Abp.DependencyInjection; namespace Volo.Abp.AspNetCore.Mvc.ModelBinding.Metadata @@ -14,14 +14,6 @@ namespace Volo.Abp.AspNetCore.Mvc.ModelBinding.Metadata [ExposeServices(typeof(IModelMetadataProvider))] public class AbpModelMetadataProvider : DefaultModelMetadataProvider { - private static readonly PropertyInfo ValidationAttributeErrorMessageStringProperty; - - static AbpModelMetadataProvider() - { - ValidationAttributeErrorMessageStringProperty = typeof(ValidationAttribute) - .GetProperty("ErrorMessageString", BindingFlags.Instance | BindingFlags.NonPublic); - } - public AbpModelMetadataProvider(ICompositeMetadataDetailsProvider detailsProvider) : base(detailsProvider) { @@ -56,7 +48,7 @@ namespace Volo.Abp.AspNetCore.Mvc.ModelBinding.Metadata { if (validationAttribute.ErrorMessage == null) { - validationAttribute.ErrorMessage = ValidationAttributeErrorMessageStringProperty.GetValue(validationAttribute) as string; + ValidationAttributeHelper.SetDefaultErrorMessage(validationAttribute); } } } diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Validation/ValidationAttributeHelper.cs b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Validation/ValidationAttributeHelper.cs new file mode 100644 index 0000000000..955b83c48f --- /dev/null +++ b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Validation/ValidationAttributeHelper.cs @@ -0,0 +1,20 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using System.Reflection; +using System.Text; + +namespace Volo.Abp.AspNetCore.Mvc.Validation +{ + public static class ValidationAttributeHelper + { + private static readonly PropertyInfo ValidationAttributeErrorMessageStringProperty = typeof(ValidationAttribute) + .GetProperty("ErrorMessageString", BindingFlags.Instance | BindingFlags.NonPublic); + + public static void SetDefaultErrorMessage(ValidationAttribute validationAttribute) + { + validationAttribute.ErrorMessage = + ValidationAttributeErrorMessageStringProperty.GetValue(validationAttribute) as string; + } + } +} diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ViewFeatures/AbpValidationHtmlAttributeProvider.cs b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ViewFeatures/AbpValidationHtmlAttributeProvider.cs index 50ac9ddf02..0f7237ed31 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ViewFeatures/AbpValidationHtmlAttributeProvider.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ViewFeatures/AbpValidationHtmlAttributeProvider.cs @@ -1,6 +1,4 @@ -using System; -using System.Collections.Generic; -using System.ComponentModel.DataAnnotations; +using System.Collections.Generic; using System.Reflection; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.DataAnnotations; @@ -12,6 +10,7 @@ using Microsoft.AspNetCore.Mvc.ViewFeatures; using Microsoft.Extensions.Localization; using Microsoft.Extensions.Options; using Volo.Abp.AspNetCore.Mvc.ModelBinding; +using Volo.Abp.AspNetCore.Mvc.Validation; using Volo.Abp.DependencyInjection; using Volo.Abp.ObjectExtending; using Volo.Abp.Validation.Localization; @@ -20,7 +19,7 @@ namespace Volo.Abp.AspNetCore.Mvc.ViewFeatures { [Dependency(ReplaceServices = true)] [ExposeServices(typeof(ValidationHtmlAttributeProvider))] - public class AbpValidationHtmlAttributeProvider + public class AbpValidationHtmlAttributeProvider : DefaultValidationHtmlAttributeProvider, ISingletonDependency { private readonly IModelMetadataProvider _metadataProvider; @@ -29,15 +28,15 @@ namespace Volo.Abp.AspNetCore.Mvc.ViewFeatures private readonly IValidationAttributeAdapterProvider _validationAttributeAdapterProvider; public AbpValidationHtmlAttributeProvider( - IOptions optionsAccessor, - IModelMetadataProvider metadataProvider, + IOptions optionsAccessor, + IModelMetadataProvider metadataProvider, ClientValidatorCache clientValidatorCache, - IValidationAttributeAdapterProvider validationAttributeAdapterProvider, - IStringLocalizerFactory stringLocalizerFactory, - IStringLocalizer validationStringLocalizer) + IValidationAttributeAdapterProvider validationAttributeAdapterProvider, + IStringLocalizerFactory stringLocalizerFactory, + IStringLocalizer validationStringLocalizer) : base( - optionsAccessor, - metadataProvider, + optionsAccessor, + metadataProvider, clientValidatorCache) { _metadataProvider = metadataProvider; @@ -47,52 +46,85 @@ namespace Volo.Abp.AspNetCore.Mvc.ViewFeatures } public override void AddValidationAttributes( - ViewContext viewContext, - ModelExplorer modelExplorer, + ViewContext viewContext, + ModelExplorer modelExplorer, IDictionary attributes) { base.AddValidationAttributes(viewContext, modelExplorer, attributes); + AddExtraPropertyValidationsAttributes(viewContext, modelExplorer, attributes); + } + protected virtual void AddExtraPropertyValidationsAttributes(ViewContext viewContext, ModelExplorer modelExplorer, IDictionary attributes) + { var nameAttribute = attributes.GetOrDefault("name"); - var propertyName = ExtraPropertyBindingHelper.ExtractExtraPropertyName(nameAttribute); - if (propertyName == null) + if (nameAttribute == null) { return; } - //NOTE: containerName can be null on controller actions..? + var extraPropertyName = ExtraPropertyBindingHelper.ExtractExtraPropertyName(nameAttribute); + if (extraPropertyName == null) + { + return; + } + //TODO: containerName can be null on controller actions..? var containerName = ExtraPropertyBindingHelper.ExtractContainerName(nameAttribute); if (containerName == null) { return; } + if (modelExplorer.Container?.ModelType == null) + { + return; + } + var extensibleObjectType = modelExplorer.Container.ModelType .GetProperty(containerName, BindingFlags.Instance | BindingFlags.Public) - .PropertyType; + ?.PropertyType; + if (extensibleObjectType == null) + { + return; + } + + var extensionPropertyInfo = ObjectExtensionManager.Instance.GetPropertyOrNull( + extensibleObjectType, + extraPropertyName + ); - var propertyInfo = ObjectExtensionManager.Instance.GetPropertyOrNull(extensibleObjectType, propertyName); + if (extensionPropertyInfo == null) + { + return; + } - modelExplorer.Metadata.As().DisplayMetadata.DisplayName = () => propertyInfo.DisplayName.Localize(_stringLocalizerFactory); + if (modelExplorer.Metadata is DefaultModelMetadata metadata) + { + metadata.DisplayMetadata.DisplayName = + () => extensionPropertyInfo.DisplayName.Localize(_stringLocalizerFactory); + } - foreach (var validationAttribute in propertyInfo.ValidationAttributes) + foreach (var validationAttribute in extensionPropertyInfo.ValidationAttributes) { var validationContext = new ClientModelValidationContext( viewContext, modelExplorer.Metadata, _metadataProvider, - attributes); + attributes + ); + + if (validationAttribute.ErrorMessage == null) + { + ValidationAttributeHelper.SetDefaultErrorMessage(validationAttribute); + } - validationAttribute.ErrorMessage = ValidationAttributeErrorMessageStringProperty.GetValue(validationAttribute) as string; + var validationAttributeAdapter = _validationAttributeAdapterProvider.GetAttributeAdapter( + validationAttribute, + _validationStringLocalizer + ); - _validationAttributeAdapterProvider.GetAttributeAdapter(validationAttribute, _validationStringLocalizer) - .AddValidation(validationContext); + validationAttributeAdapter.AddValidation(validationContext); } } - - private static readonly PropertyInfo ValidationAttributeErrorMessageStringProperty = typeof(ValidationAttribute) - .GetProperty("ErrorMessageString", BindingFlags.Instance | BindingFlags.NonPublic); - } }