Проверьте поле MVC на стороне клиента

У меня проблема с проверкой одного поля на стороне клиента. Вот мой код:

Модель:

 public class Registration
    {
        public int Id { get; set; }
        [IsUserExistAttribute(ErrorMessage = "Email already exists!")]
        [EmailAddress(ErrorMessage = "Please enter valid Email")]
        [Required(ErrorMessage = "Email is required")]
        public string Email
        {
            get; set;

        }
        [MustBeTrue(ErrorMessage = "Please Accept the Terms & Conditions")]
        public bool TermsAndConditions { get; set; }


    }

ValidationAttribute:

public class IsUserExistAttribute : ValidationAttribute,IClientValidatable
    {
        public override bool IsValid(object email)
        {
            DemoDbContext demoContext=new DemoDbContext();
            string emailString = Convert.ToString(email);
            if (demoContext.Registrations.Any(a=>a.Email.Contains(emailString)))
            {
                return false;
            }
            return true;
        }

        public IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, ControllerContext context)
        {
            yield return new ModelClientValidationRule
            {
                ErrorMessage = this.ErrorMessage,
                ValidationType = "emailvalidate"
            };
        }
    }

Посмотреть:

@using (Html.BeginForm())
{
    @Html.AntiForgeryToken()

    <div class="form-horizontal">
        <h4>Registration</h4>
        <hr />
        @Html.ValidationSummary(true, "", new { @class = "text-danger" })
        <div class="form-group">
            @Html.LabelFor(model => model.Email, htmlAttributes: new { @class = "control-label col-md-2" })
            <div class="col-md-10">
                @Html.EditorFor(model => model.Email, new { htmlAttributes = new { @class = "form-control" } })
                @Html.ValidationMessageFor(model => model.Email, "", new { @class = "text-danger" })
            </div>
        </div>

        <div class="form-group">
            @Html.LabelFor(model => model.TermsAndConditions, htmlAttributes: new { @class = "control-label col-md-2" })
            <div class="col-md-10">
                <div class="checkbox">
                    @Html.EditorFor(model => model.TermsAndConditions)
                    @Html.ValidationMessageFor(model => model.TermsAndConditions, "", new { @class = "text-danger" })
                </div>
            </div>
        </div>

        <div class="form-group">
            <div class="col-md-offset-2 col-md-10">
                <input type="submit" value="Create" class="btn btn-default" />
            </div>
        </div>
    </div>
}

Все это работает нормально, но мой вопрос: этот IsUserExistAttribute не проверяет его на стороне клиента, на стороне сервера он проверяет и выдает сообщение, как будто электронная почта уже существует!

Но я хочу, чтобы он также проверял и клиентскую часть. Итак, каков хороший способ достичь этого? Другой подход также приветствуется:)

Я пробовал что-то вроде этого, кажется, не имеет успеха:

 $.validator.addMethod("emailvalidate", function (value, element) {
            var is_valid = false;
            $.ajax({
                // as before...
                async: false,
                success: function (data) {
                    is_valid = data === 'True';
                }
            });
            return is_valid;
        }, "Username not available.");

1 ответ

Решение

MVC уже поставляется с RemoteAttribute для проверки на стороне клиента (см. Практическое руководство. Реализация удаленной проверки в ASP.NET MVC), поэтому нет смысла пытаться изобретать колесо. (Как примечание, ваш в настоящее время отсутствует $.validator.unobtrusive.adapters.add() метод, необходимый для добавления правил проверки на стороне клиента).

Но есть несколько проблем с вашим текущим атрибутом проверки. Атрибут проверки не должен иметь доступ к базе данных, и вы сделали невозможным модульное тестирование своего кода. И вы будете повторять код в атрибуте снова в методе контроллера, который вызывается функцией ajax, нарушая принцип DRY и усложняя поддержание вашего кода.

Вместо этого создайте приватный метод в вашем контроллере (или публичный метод в отдельной службе) для вашего кода базы данных, например

private bool IsEmailUnique(string email)
{
    return !db.Registrations.Any(a => a.Email.Contains(email)))
}

Затем для проверки на стороне клиента украсьте свое имущество с помощью RemoteAttribute

[Remote("IsEmailValid", "ControllerName", ErorMessage = "...")]
public string Email { get; set; }

и добавить метод контроллера

public JsonResult IsEmailValid(string email)
{
    bool isValid = IsEmailUnique(email);
    return Json(isValid, JsonRequestBehavior.AllowGet);
}

и затем, если вы также хотите иметь проверку на стороне сервера при отправке формы, вызовите тот же метод и, если он недействителен, добавьте ModelStateError

public ActionResult Register(Registration model)
{
    bool isValid = IsEmailUnique(model.Email);
    if (!isValid)
    {
        ModelState.AddModelError("Email", "...");
    }
    if (!ModelState.IsValid)
    {
        return View(model);
    }
    // save and redirect
}
Другие вопросы по тегам