Custom data annotations not displaying error on postback

I have looked at a number of posts on this topic - custom server side validation - here and here and here (I believe this is for MVC4) but none seem to address this for me.

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 tutorial and have recreated his data validation class with no changes.

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

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.

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.

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.

OK so why does it display normal annotation validation errors and not the custom validation errors?

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)?

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.

    public class CompanyDetail
    {
         public int CompanyDetailId { get; set; }
         public string CompanyName { get; set; }
         public string ABN { get; set; }
    }

A CompanyDetailViewModel with the data annotations added:

 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; }
}

A controller: public class CompanyDetailsController : Controller { private ApplicationDbContext _context;

    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);
    }

}

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

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

and the actual custom validation class:

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 < _chars.Length; i++)
            {
                var valueAsString = value.ToString();
                if (valueAsString.Contains(_chars[i]))
                {
                    var errorMessage = FormatErrorMessage(validationContext.DisplayName);
                    return new ValidationResult(errorMessage);
                }
            }
        }
        return ValidationResult.Success;
    }
}

I figured it out in your code you are using

<span asp-validation-for="number" class="text-danger" />

Thats default html generated by Visual Studio (no idea why). You need to add the closing tag. Use it like

<span asp-validation-for="number" class="text-danger" ></span>

and it'll show the error messages right under the field.


What you have to do is specify in the view where you want your custom error message to be shown.

example:

<div>
    @Html.ValidationMessage("CreditRating")
</div>

Then returning a ValidationResult that relates to the "member" CreditRating will show in that part of the view. member is in quotes because the name can actually be any name, does not have to be a real name of a real property.

   results.Add(new ValidationResult("NO NO NO", new[] { "CreditRating" }));

I agree that this is surprising behavior. I seems like custom errors are handled differently. maybe some naming convention that is not documented.

链接地址: http://www.djcxy.com/p/56592.html

上一篇: ASP.NET MVC数据注解持久层之间

下一篇: 自定义数据注释在回发时不显示错误