1

I have an ASP.NET Core 2 project in which I use annotations to validate a currency field, like this:

public class Record {
    public const string CurrencyRegex = @"^[$]?\d+[,.]?\d?\d? ?[€$]?$";

[RegularExpression(Record.CurrencyRegex, ErrorMessage = "Invalid currency format")]
public string Budget { get; set; }

The problem is the decimal separator ([,.]?\d?\d?) is not perfect. I need the expression be sensible of the current context culture. If is UK/US, the decimal separator should be validated as ., but id there, say FR culture, the decimal should be considered as ,

How can I use a "context-dependent constant" as RegularExpression attribute value, if possible?

serge
  • 13,940
  • 35
  • 121
  • 205

1 Answers1

3

This is not possible. Any values passed to attributes must be compile-time constants. But Thread.CurrentThread.CurrentCulture or similar is a runtime variable.

What you can do is define the Budget as decimal or double and let the ModelBinder parse the input string using the current culture. (You will have to transport the currency symbol in an additional field.)

Or handle the validation by implementing IValidatableObject on the model and remove the [RegularExpression]:

using System.Globalization;
using System.Text.RegularExpressions;

public class Record : IValidatableObject {

     public string Budget { get; set; }

     public IEnumerable<ValidationResult> Validate(ValidationContext validationContext) {

        var currentDecimalSeparator =
            CultureInfo.CurrentCulture.NumberFormat.NumberDecimalSeparator;

        // no need to espace literal dot '.' 
        // because it is used inside a character class '[.]'
        var currencyPattern = @"^[$]?\d+[" + currentDecimalSeparator + @"]?\d?\d? ?[€$]?$";

        if (!Regex.IsMatch(Budget, currencyPattern)) {
             yield return new ValidationResult(
                 $"Invalid currency format (use '{currentDecimalSeparator}' for decimal places).",
                 new[] { "Budget" }
             );
        }
     }
}
Georg Patscheider
  • 9,357
  • 1
  • 26
  • 36