0

Im using dotnet core 3.1.403, and developing an api.

Here, seems to be working: ASP.NET Core custom validation attribute localization

https://blogs.msdn.microsoft.com/mvpawardprogram/2017/01/03/asp-net-core-mvc/

https://github.com/aspnet/Mvc/issues/5282

My Adapter Provider

public class CustomValidatiomAttributeAdapterProvider : IValidationAttributeAdapterProvider
{
    private readonly IValidationAttributeAdapterProvider _baseProvider = 
        new ValidationAttributeAdapterProvider();
    public IAttributeAdapter GetAttributeAdapter(ValidationAttribute attribute, 
        IStringLocalizer stringLocalizer)
    {
        if (attribute is DateTimeAttribute dateTimeAttribute) {
            return new DateTimeAttributeAdapter(dateTimeAttribute, stringLocalizer);
        }
        else
        {
            return _baseProvider.GetAttributeAdapter(attribute, stringLocalizer);
        }
    }
}

My Adapter

public class DateTimeAttributeAdapter : AttributeAdapterBase<DateTimeAttribute>
{
    public DateTimeAttributeAdapter(DateTimeAttribute attribute, IStringLocalizer 
    stringLocalizer) : base(attribute, stringLocalizer)
    {
    }

    public override void AddValidation(ClientModelValidationContext context) 
    {
    }

    public override string GetErrorMessage(ModelValidationContextBase validationContext)
    {
        var metadata = validationContext.ModelMetadata;
        return GetErrorMessage(metadata, metadata.GetDisplayName());
    }
}

My Attribute

public class DateTimeAttribute : ValidationAttribute
{
    public DateTimeAttribute() : base(() => "{0} é uma data inválida")
    {
    }

    protected override ValidationResult IsValid(object value, ValidationContext 
    validationContext)
    {
        DateTime dateTime;
        bool success = DateTime.TryParseExact(
                    (value as string).Trim(),
                    new string[] {
                        "yyyy'-'MM'-'dd' 'HH':'mm':'ss",
                        "yyyy'-'MM'-'dd'T'HH':'mm':'ss",
                        "yyyy'-'MM'-'dd",
                    },
                    DateTimeFormatInfo.InvariantInfo,
                    DateTimeStyles.RoundtripKind,
                    out dateTime
                );

        if (!success)
        {
            return new ValidationResult(FormatErrorMessage(validationContext.DisplayName));
        }

        return ValidationResult.Success;
    }
}  

Here is my Startup.cs

    public void ConfigureServices(IServiceCollection services)
    {
        services.AddLocalization(opt => {
            opt.ResourcesPath = "Resources";
        });

        services.AddControllers()
            .AddDataAnnotationsLocalization(opt => {
                opt.DataAnnotationLocalizerProvider = (type, factory) => factory.Create(typeof(SharedResources));
            });

        
            
        services.AddSingleton<IValidationAttributeAdapterProvider, CustomValidatiomAttributeAdapterProvider>();
    }

But, the GetAttributeAdapter method is never called. What is wrong here?

UPDATE

The problem is solved BY NOT calling the base constructor on ValidationAttribute. See Brando Zhang Answer

Instead of:

    public DateTimeAttribute() : base(() => "{0} é uma data 
        inválida")
    {
    }

I do:

public DateTimeAttribute() : base()
{
    ErrorMessage = "{0} is an invalid";
}
  • Could you please share the codes about how you use the ` DateTimeAttribute` and the SharedResources? I have created a test demo on my side and it works well. The CustomValidatiomAttributeAdapterProvider has fired. [Image](https://i.stack.imgur.com/PQIi8.gif). – Brando Zhang Nov 02 '20 at 07:52
  • Thank you for this reply. I will up my complete code to github and share de link. Could you do up your working code too? –  Nov 02 '20 at 15:40
  • I don't suggest you share your production project, you could create a simple project which could reproduce this issue. Notice: please don't include any personal information in your shared project. – Brando Zhang Nov 03 '20 at 03:01
  • @BrandoZhang here is my code: https://github.com/ArthDevRepo/validationattributeadapterprovider, as you suggested, it is not a production code –  Nov 03 '20 at 15:12

1 Answers1

0

According to your description and codes, I found you have use the base(() => "{0} é uma data inválida") to use parent validation provider.

This is the reason why your CustomValidatiomAttributeAdapterProvider doesn't be called.

I suggest you could try to modify the RegisterPersonDto class BirthDate property like below:

public class RegisterPersonDto
{
    [Display(Name = "Name")]
    [Required]
    public string Name { get; set; }

    [Display(Name = "Date of Birth")]
    [DateTime([DateTime(ErrorMessage ="tested")])]
    public string BirthDate { get; set; }
} 
Brando Zhang
  • 22,586
  • 6
  • 37
  • 65