title: Custom Validation for nested model in .net core
body: <p>I am trying to validate a nested model using custom validation. But the problem is <code>AttributeAdapterBase.AddValidation</code> function is never called on nested model. However it works well with simple class property</p>
  <p>Custom required validation attribute:</p>
  <pre><code>    public interface IId
      {
          long Id { get; set; }
      }
  
      public class Select2RequiredAttribute : RequiredAttribute
      {
          public Select2RequiredAttribute(string errorMessage = &quot;&quot;) : base()
          {
              ErrorMessage = errorMessage;
          }
  
          protected override ValidationResult IsValid(object value, ValidationContext validationContext)
          {
              Type t = value.GetType();
  
              if (typeof(IId).IsAssignableFrom(t))
              {
                  if ((value as IId).Id == 0)
                  {
                      return new ValidationResult(ErrorMessage);
                  }
              }
              else
              {
                  return new ValidationResult(ErrorMessage);
              }
  
              return ValidationResult.Success;
          }
  }
  </code></pre>
  <p>Attribute adapter base:</p>
  <pre><code>public class Select2RequiredAttributeAdapter : AttributeAdapterBase&lt;Select2RequiredAttribute&gt;
  {
      public Select2RequiredAttributeAdapter(Select2RequiredAttribute attribute, IStringLocalizer stringLocalizer) : base(attribute, stringLocalizer)
      {
      }
  
      public override void AddValidation(ClientModelValidationContext context)
      {
          MergeAttribute(context.Attributes, &quot;data-val&quot;, &quot;true&quot;);
          MergeAttribute(context.Attributes, &quot;data-val-select2-required&quot;, GetErrorMessage(context));
      }
  
      public override string GetErrorMessage(ModelValidationContextBase validationContext)
      {
          return Attribute.ErrorMessage ?? GetErrorMessage(validationContext.ModelMetadata, validationContext.ModelMetadata.GetDisplayName());
      }
  }
  </code></pre>
  <p>Adapter provider:</p>
  <pre><code>public class Select2RequiredAdapterProvider : IValidationAttributeAdapterProvider
  {
      private readonly IValidationAttributeAdapterProvider _baseProvider = new ValidationAttributeAdapterProvider();
  
      public IAttributeAdapter GetAttributeAdapter(ValidationAttribute attribute, IStringLocalizer stringLocalizer)
      {
          if (attribute is Select2RequiredAttribute)
          {
              return new Select2RequiredAttributeAdapter(attribute as Select2RequiredAttribute, stringLocalizer);
          }
          else
          {
              return _baseProvider.GetAttributeAdapter(attribute, stringLocalizer);
          }
      }
  }
  </code></pre>
  <p><code>Startup.cs</code>:</p>
  <pre><code>services.AddSingleton&lt;IValidationAttributeAdapterProvider, Select2RequiredAdapterProvider&gt;();
  </code></pre>
  <p>Model classes:</p>
  <pre><code>public interface IBaseBriefViewModel : IId
  {
      string Name { get; set; }
  }
  
  public class BaseBriefViewModel : IBaseBriefViewModel
  {
      public virtual long Id { get; set; }
      public string Name { get; set; }
  }
  
  public class UserViewModel 
  {
      public long Id { get; set; }
      public string Name { get; set; }
      [Select2Required(&quot;Branch is required.&quot;)]
      public BaseBriefViewModel Branch { get; set; }
  }
  </code></pre>
  <p>Branch select 2 partial view:</p>
  <pre><code>@model DataLibrary.ViewModels.BriefViewModels.BaseBriefViewModel
  @{
      var elementId = ViewData[&quot;ElementId&quot;] != null &amp;&amp; !string.IsNullOrEmpty(ViewData[&quot;ElementId&quot;].ToString()) ? ViewData[&quot;ElementId&quot;].ToString() : &quot;branch-id&quot;;
  }
  
  &lt;div class=&quot;form-group&quot;&gt;
      &lt;label&gt;Branch: &lt;span class=&quot;text-danger&quot;&gt;&lt;/span&gt;&lt;/label&gt;
      &lt;div class=&quot;row&quot;&gt;
          &lt;div class=&quot;@select2Class&quot;&gt;
              @Html.DropDownListFor(model =&gt; model.Id, new List&lt;SelectListItem&gt;() {
             new SelectListItem()
             {
                 Value = (Model!=null&amp;&amp;Model.Id&gt;0)?Model.Id.ToString():&quot;&quot;,
                 Text = (Model!=null&amp;&amp;Model.Id&gt;0)?Model.Name:&quot;&quot;,
                 Selected = (Model!=null&amp;&amp;Model.Id&gt;0)?true:false,
             }}, new { @id = elementId, @class = &quot;form-control disable-field&quot;})
              @Html.ValidationMessageFor(model =&gt; model.Id, &quot;&quot;, new { @class = &quot;text-danger&quot; })
          &lt;/div&gt;
      &lt;/div&gt;
  &lt;/div&gt;
  
  &lt;script&gt;
      $(function () {
          var id = &quot;#&quot; + &quot;@elementId&quot;;
          var url = '/Branch/GetBranchsForSelect2';
          var dataArray = function (params) {
              params.page = params.page || 1;
              return {
                  prefix: params.term,
                  pageSize: pageSize,
                  pageNumber: params.page,
              };
          };
          Select2AutoCompleteAjax(id, url, dataArray, pageSize, &quot;---Branch---&quot;);
      });
  &lt;/script&gt;
  </code></pre>
  <p>All this code works well for server side. But for better user experience I want to show error before submitting form. How can I achieve this? I want to use this <code>BaseBriefViewModel</code> for a lot of Select2 in the project. So hard coding a static error message is not a good idea. What I really want to do is pass a error message from parent object. Like <em>Branch is required</em> in this specific case. Maybe in some other class I might pass <em>Product is required</em></p>
  <p>Any direction will be appreciated</p>