title: Passing data from custom validation attribute to page/view
body: <p>Let's say I have a custom validation attribute:</p>
  
  <pre><code>public class CustomAttribute : ValidationAttribute
  {
      public override string FormatErrorMessage(string name)
      {
          return string.Format(CultureInfo.CurrentCulture, ErrorMessageString, name);
      }
      protected override ValidationResult IsValid(object value, ValidationContext validationContext)
      {
  
          var customErrorString = "You did something wrong!"; //How to pass this to the localized string defined in the resource file?
  
          if(SomethingIsInvalid())
              return new ValidationResult(FormatErrorMessage(validationContext.MemberName));
  
          return ValidationResult.Success;
      }
  }
  
  public class CustomAttributeAdapter : AttributeAdapterBase&lt;CustomAttribute&gt;
  {
      public CustomAttributeAdapter(CustomAttribute attribute, IStringLocalizer stringLocalizer)
          : base(attribute, stringLocalizer)
      {
      }
  
      public override void AddValidation(ClientModelValidationContext context)
      {
          if (context == null)
          {
              throw new ArgumentNullException(nameof(context));
          }
  
          MergeAttribute(context.Attributes, "data-val", "true");
      }
  
      public override string GetErrorMessage(ModelValidationContextBase validationContext)
      {
          if (validationContext == null)
          {
              throw new ArgumentNullException(nameof(validationContext));
          }
  
          return GetErrorMessage(validationContext.ModelMetadata, validationContext.ModelMetadata.GetDisplayName());
      }
  }
  </code></pre>
  
  <p>How can I pass, let's say, a string from the data annotation to the validation tag? For example:</p>
  
  <pre><code>[Custom(ErrorMessage = "CustomValidationMessage")]
  public string ValidateThis { get; set; }
  </code></pre>
  
  <p><code>CustomValidationMessage</code> is defined in a resource file and results to <code>"This is invalid:"</code></p>
  
  <p>Now my question is, how can I pass <code>customErrorString</code> from the validation attribute to the localized string so it shows on the validation tag like this:</p>
  
  <pre><code>&lt;span id="validation-span" asp-validation-for="@Model.ValidateThis" class="text-danger"&gt;This is invalid: You did something wrong!&lt;/span&gt;
  </code></pre>
  
  <p>I hope my question is clear. If not, feel free to ask for more details.</p>
  
  <p>EDIT: I got it to work:</p>
  
  <pre><code>public class CustomAttribute : ValidationAttribute
  {
      //Create property to hold our custom error string
      public string CustomErrorString { get; set; }
  
      public override string FormatErrorMessage(string name)
      {
          return string.Format(CultureInfo.CurrentCulture, ErrorMessageString, name);
      }
      protected override ValidationResult IsValid(object value, ValidationContext validationContext)
      {
          //Set the custom error string property.
          CustomErrorString = "You did something wrong!"; 
  
          if(SomethingIsInvalid())
              return new ValidationResult(FormatErrorMessage(validationContext.MemberName));
  
          return ValidationResult.Success;
      }
  }
  
  public class CustomAttributeAdapter : AttributeAdapterBase&lt;CustomAttribute&gt;
  {
      //Declare class variable to hold the attribute's custom error string.
      private string _customErrorString = string.empty;
  
      public CustomAttributeAdapter(CustomAttribute attribute, IStringLocalizer stringLocalizer)
          : base(attribute, stringLocalizer)
      {
          //Set the adapter's custom error string according to the attribute's custom error string
          if(!string.IsNullOrEmpty(attribute.CustomErrorString))
              _customErrorString = attribute.CustomErrorString;
      }
  
      public override void AddValidation(ClientModelValidationContext context)
      {
          if (context == null)
          {
              throw new ArgumentNullException(nameof(context));
          }
  
          MergeAttribute(context.Attributes, "data-val", "true");
      }
  
      public override string GetErrorMessage(ModelValidationContextBase validationContext)
      {
          if (validationContext == null)
          {
              throw new ArgumentNullException(nameof(validationContext));
          }
  
          //Pass the custom error string instead of member name
          return GetErrorMessage(validationContext.ModelMetadata, _customErrorString);
      }
  }
  </code></pre>
  
  <p>After you do all of this, you can then set your resource string like this:</p>
  
  <pre><code>[Custom(ErrorMessage = "CustomValidationMessage")]
  public string ValidateThis { get; set; }
  </code></pre>
  
  <p>Where <code>CustomValidationMessage</code> results in <code>"This is invalid: {0}"</code></p>
  
  <p>Normally, <code>{0}</code> would result in the localized member name of the property. But because we passed the custom error string in the adapter, it will be set to the custom error message.</p>
  
  <p>It might be a little dirty, but it gets the job done.</p>