Custom data annotations not displaying error on postback - ASP.NET core MVC6
<p>I have looked at a number of posts on this topic - custom server side validation - <a href="https://stackoverflow.com/questions/21196766/custom-dataannotation-in-asp-net-mvc-not-working">here</a> and <a href="https://stackoverflow.com/questions/24277262/custom-validator-message-not-displaying">here</a> and <a href="https://stackoverflow.com/questions/12968542/use-client-side-validation-when-custom-required-attribute-is-used/12968598#12968598">here</a> (I believe this is for MVC4) but none seem to address this for me.</p>

<p>I have created a basic MVC6 project (two textboxes) just to test dataannotations and still cannot get this to work. I am using, as a basis, this <a href="http://www.c-sharpcorner.com/UploadFile/abhikumarvatsa/custom-data-annotations-or-custom-validation-attributes-in-m/" rel="nofollow noreferrer">tutorial</a> and have recreated his data validation class with no changes.  </p>

<p>I am not using the actual model but rather a viewModel that if validation is successful updates the database through assignment to the model. </p>

<p>I am not interested in a successful validation here but whether, upon a "(ModelState.IsValid)" equal to "False", it displays the error message under the textbox.</p>

<p>I have stepped through it and find that it does step through the actual custom validator and it certainly gives a model state of false on the custom validation - returns the view - but no error message displays.</p>

<p>If, however, I remove everything from the textbox - make it empty - the viewmodel is returned but this time it comesup with the "Required" error in red.. that is, the error messages work for data annotations just not custom annotations.</p>

<p>OK so <em>why does it display normal annotation validation errors and not the custom validation errors</em>? </p>

<p>Is this as a result of ASP.NET core or is it just the way I am returning the viewmodel (eg an error by me much more likely)?</p>

<p>I have decided to include all the moving parts as it might be any one of them not being correct or at issue. So thats a model, a viewmodel based on the model, a controller and the custom validator class as per the tutorial.</p>

<pre><code>    public class CompanyDetail
    {
         public int CompanyDetailId { get; set; }
         public string CompanyName { get; set; }
         public string ABN { get; set; }
    }
</code></pre>

<p>A CompanyDetailViewModel with the data annotations added:</p>

<pre><code> public class CompanyDetailsViewModel
{
    public int CompanyDetailsId { get; set; }

    [ExcludeChar("/")]
    [Required(ErrorMessage = "A Company Name is required")]
    [Display(Name = "Company Name:")]
    [StringLength(100)]
    public string CompanyName { get; set; }

    [Required(ErrorMessage = "An ABN is required")]
    [CheckValidABN(ErrorMessage = "This is not a valid ABN")]
    [Display(Name = "ABN:")]
    public string ABN { get; set; }
}
</code></pre>

<p>A controller:
    public class CompanyDetailsController : Controller
    {
        private ApplicationDbContext _context;</p>

<pre><code>    public CompanyDetailsController(ApplicationDbContext context)
    {
        _context = context;    
    }


    // GET: CompanyDetailsViewModels/Edit/5
    public IActionResult Edit()
    {

        var Company = _context.CompanyDetails.First();
        if (Company == null)
        {
            return HttpNotFound();
        }
        var CompanyDetails = new CompanyDetailsViewModel();

        CompanyDetails.CompanyDetailsId = Company.CompanyDetailId;
        CompanyDetails.CompanyName = Company.CompanyName;
        CompanyDetails.ABN = Company.ABN;

        return View(CompanyDetails);
    }

    // POST: CompanyDetailsViewModels/Edit/5
    [HttpPost]
    [ValidateAntiForgeryToken]
    public IActionResult Edit(CompanyDetailsViewModel companyDetailsViewModel)
    {
        if (ModelState.IsValid)
        {
            CompanyDetail Company = _context.CompanyDetails.First();
            var CompanyDetails = new CompanyDetailsViewModel();

            Company.CompanyName = CompanyDetails.CompanyName;
            CompanyDetails.ABN = Company.ABN;

            _context.CompanyDetails.Update(Company);
            _context.SaveChanges();

            return RedirectToAction("Index");
        }
        return View(companyDetailsViewModel);
    }

}
</code></pre>

<p>A view with a (vanilla scaffolded) form - it uses the viewmodel as the model:</p>

<pre><code>&lt;form asp-action="Edit"&gt;
&lt;div class="form-horizontal"&gt;
    &lt;h4&gt;CompanyDetailsViewModel&lt;/h4&gt;
    &lt;hr /&gt;
    &lt;div asp-validation-summary="ValidationSummary.ModelOnly" class="text-danger"&gt;&lt;/div&gt;
    &lt;input type="hidden" asp-for="CompanyDetailsId" /&gt;
    &lt;div class="form-group"&gt;
        &lt;label asp-for="ABN" class="col-md-2 control-label"&gt;&lt;/label&gt;
        &lt;div class="col-md-10"&gt;
            &lt;input asp-for="ABN" class="form-control" /&gt;
            &lt;span asp-validation-for="ABN" class="text-danger" /&gt;
        &lt;/div&gt;
    &lt;/div&gt;
    &lt;div class="form-group"&gt;
        &lt;label asp-for="CompanyName" class="col-md-2 control-label"&gt;&lt;/label&gt;
        &lt;div class="col-md-10"&gt;
            &lt;input asp-for="CompanyName" class="form-control" /&gt;
            &lt;span asp-validation-for="CompanyName" class="text-danger" /&gt;
        &lt;/div&gt;
    &lt;/div&gt;
    &lt;div class="form-group"&gt;
        &lt;div class="col-md-offset-2 col-md-10"&gt;
            &lt;input type="submit" value="Save" class="btn btn-default" /&gt;
        &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;
</code></pre>

<p></p>

<p>and the actual custom validation class:</p>

<pre><code>public class ExcludeChar : ValidationAttribute
{
    private readonly string _chars;
    public ExcludeChar(string chars)
    : base("{0} contains invalid character.")
    {
        _chars = chars;
    }


    protected override ValidationResult IsValid(object value, ValidationContext validationContext)
    {
        if (value != null)
        {
            for (int i = 0; i &lt; _chars.Length; i++)
            {
                var valueAsString = value.ToString();
                if (valueAsString.Contains(_chars[i]))
                {
                    var errorMessage = FormatErrorMessage(validationContext.DisplayName);
                    return new ValidationResult(errorMessage);
                }
            }
        }
        return ValidationResult.Success;
    }
}
</code></pre>