Custom validation not working in plugin

1 month ago
Hello  @all,

I'm working on 6 plugins but the custom data validation does not work in any of them.
One example:
My plugin creates a new page on the public store, on the "my account" page.
I use a model class named "ProductInquiryModel" and therefore I created a custom validation class "ProductInquiryValidator : BaseNopValidator<ProductInquiryModel>"

The breakpoint in the constructor (where the "RuleFor"-Parts are) does not get called at any time.
I did check these validators in the nop.web project, which there work fine.

Validator class:
using System;
using System.Linq;
using Acea.Plugin.Widgets.ProductInquiry.Models;
using FluentValidation;
using Nop.Core;
using Nop.Core.Domain.Customers;
using Nop.Services.Directory;
using Nop.Services.Localization;
using Nop.Web.Framework.Validators;
using Nop.Web.Models.Customer;

namespace Acea.Plugin.Widgets.ProductInquiry.Validators
{
    public partial class ProductInquiryValidator : BaseNopValidator<ProductInquiryModel>
    {
        public ProductInquiryValidator(ILocalizationService localizationService,
            IStateProvinceService stateProvinceService,
            CustomerSettings customerSettings)
        {
            RuleFor(x => x.CustomerEMail).NotEmpty().WithMessageAwait(localizationService.GetResourceAsync("Account.Fields.Email.Required"));
            RuleFor(x => x.CustomerEMail).EmailAddress().WithMessageAwait(localizationService.GetResourceAsync("Common.WrongEmail"));
            RuleFor(x => x.CustomerFirstName).NotEmpty().WithMessageAwait(localizationService.GetResourceAsync("Account.Fields.FirstName.Required"));

        }
    }
}


Model class:
using Nop.Web.Framework.Models;
using Nop.Web.Framework.Mvc.ModelBinding;
using Microsoft.AspNetCore.Mvc.Rendering;
using System.ComponentModel.DataAnnotations;

namespace Acea.Plugin.Widgets.ProductInquiry.Models
{
    public record ProductInquiryModel : BaseNopModel
    {
        public ProductInquiryModel()
        {
        }

        public int StoreId { get; set; }

        [NopResourceDisplayName("Plugins.Widgets.ProductInquiry.ProductId.Label")]
        public string ProductId { get; set; }

        [NopResourceDisplayName("Plugins.Widgets.ProductInquiry.ProductName.Label")]
        public string ProductName { get; set; }

        [NopResourceDisplayName("Plugins.Widgets.ProductInquiry.ProductSku.Label")]
        public string ProductSku { get; set; }

        [NopResourceDisplayName("Plugins.Widgets.ProductInquiry.ProductUrl.Label")]
        public string ProductUrl { get; set; }

        public int CustomerId { get; set; }

        [NopResourceDisplayName("Plugins.Widgets.ProductInquiry.CustomerCompany.Label")]
        public string CustomerCompany { get; set; }

        [NopResourceDisplayName("Plugins.Widgets.ProductInquiry.CustomerFirstName.Label")]
        public string CustomerFirstName { get; set; }

        [NopResourceDisplayName("Plugins.Widgets.ProductInquiry.CustomerLastName.Label")]
        public string CustomerLastName { get; set; }

        [NopResourceDisplayName("Plugins.Widgets.ProductInquiry.CustomerPhone.Label")]
        public string CustomerPhone { get; set; }

        [DataType(DataType.EmailAddress)]
        [NopResourceDisplayName("Plugins.Widgets.ProductInquiry.CustomerEMail.Label")]
        public string CustomerEMail { get; set; }

        [NopResourceDisplayName("Plugins.Widgets.ProductInquiry.Subject.Label")]
        public string Subject { get; set; }

        [NopResourceDisplayName("Plugins.Widgets.ProductInquiry.Text.Label")]
        public string Text { get; set; }

        [NopResourceDisplayName("Plugins.Widgets.ProductInquiry.SendCopyToCustomer.Label")]
        public bool SendCopyToCustomer { get; set; }
    }
}


View file:
@using Nop.Web.Framework.UI
@using Nop.Core
@using Nop.Core.Domain.Catalog
@using Nop.Core.Domain.Seo
@using Nop.Services.Configuration
@using Nop.Services.Html
@using Acea.Plugin.Widgets.ProductInquiry.Models
@using Microsoft.AspNetCore.Mvc.TagHelpers

@model ProductInquiryModel

@{
    Layout = "_ColumnsTwo";
    NopHtml.AddTitleParts(T("Plugins.Widgets.ProductInquiry.Text.Heading").Text);
}

<div class="page account-page">
    <div class="page-title">
        <h1>@T("Plugins.Widgets.ProductInquiry.Text.Heading").Text</h1>
    </div>
    <div class="page-body">
        <form asp-controller="ProductInquiry" asp-action="Create" method="post">
            <div asp-validation-summary="ModelOnly" class="message-error"></div>

            <div class="fieldset">
                <div class="title">
                    <strong>Contact us</strong>
                </div>
                <div class="form-fields">
                    @Html.HiddenFor(model => model.ProductId)
                    @Html.HiddenFor(model => model.ProductUrl)

                    <div class="inputs">
                        <label asp-for="ProductSku" asp-postfix=":"></label>
                        <nop-editor asp-for="ProductSku" html-attributes="@(new { disabled = true })" />
                    </div>

                    <div class="inputs">
                        <label asp-for="ProductName" asp-postfix=":"></label>
                        @Html.HiddenFor(model => model.ProductName)
                        <nop-editor asp-for="ProductName" html-attributes="@(new { disabled = true })" />
                    </div>

                    <div class="inputs">
                        <label asp-for="@Model.CustomerFirstName" asp-postfix=":"></label>
                        <input asp-for="@Model.CustomerFirstName" />
                        <nop-required />
                        <span asp-validation-for="@Model.CustomerFirstName"></span>
                    </div>

                    <div class="inputs">
                        <label asp-for="CustomerLastName" asp-postfix=":"></label>
                        <nop-editor asp-for="CustomerLastName" name="CustomerLastName" />
                    </div>

                    <div class="inputs">
                        <label asp-for="CustomerPhone" asp-postfix=":"></label>
                        <nop-editor asp-for="CustomerPhone" name="CustomerPhone" />
                    </div>

                    <div class="inputs">
                        <label asp-for="@Model.CustomerEMail" asp-postfix=":"></label>
                        <input asp-for="@Model.CustomerEMail" />
                        <nop-required />
                        <span asp-validation-for="@Model.CustomerEMail"></span>
                    </div>

                    <div class="inputs">
                        <label asp-for="CustomerCompany" asp-postfix=":"></label>
                        <nop-editor asp-for="CustomerCompany" name="CustomerCompany" />
                    </div>

                    <div class="inputs">
                        <label asp-for="Subject" asp-postfix=":"></label>
                        <nop-editor asp-for="Subject" name="Subject" />
                    </div>

                    <div class="inputs">
                        <label asp-for="Text" asp-postfix=":"></label>
                        <nop-textarea asp-for="Text" name="Text" />
                    </div>
                    
                    <div class="inputs">
                        <label for="SendCopyToCustomer" />
                        <nop-editor asp-for="SendCopyToCustomer" name="SendCopyToCustomer" />
                    </div>
                    
                    <div class="buttons">
                        <input type="submit" name="add-request" class="button-1" value="@T("Plugins.Widgets.ProductInquiry.Buttons.SubmitInquiry.Text")" />
                    </div>
                    
                </div>
            </div>
            
        </form>
    </div>
</div>


As you can see, I tried
<input asp-for="@Model.CustomerFirstName" />
but before I also tried
<input asp-for="CustomerFirstName" />
and
<nop-editor asp-for="@Model.CustomerFirstName" />

I was a little happy that FINALLY there was a validation message for the email field:
"Please enter a valid email address."
but then I noticed that this is NOT the message that the validation class should show
but it comes from the jquery itself:


also, the hint "email is required" does not show up at any time, only "Please enter a valid email address.".

Any help/hint is highly appreciated
1 month ago
There is a limitation on the assemblies from which validators are registered. They must start with "Nop" (see the code here), all core assemblies and our plugins follow this rule.
But you can customize this for your needs.
See also this topic.