Отменить remote валидацию для определённого action

169
20 января 2019, 04:40

Можно ли как нибудь отменить действие валидации Remote на определённой странице представления?

Подробней:

Есть валидация на поле Name

[Required]
[StringLength(15, MinimumLength = 3)]
[Remote(action: "CheckName", controller: "Validation", ErrorMessage = "Эй! Уф, нэ пеши сюда ето имя:-[ Оно уже есь же, эсь жи!!")]
[Display(Name = "Название компании")]
public string Name { get; set; }

так же есть страница Create для чего собственно и нужна валидация!

И ещё я сделал страницу Edit!

И при редактировании компании, даже если её не меняешь, приложение отказывается сохранять изменения, пока не изменишь имя, так как оно уже существует. Можно ли как нибудь отменить действие валидации для этой страницы?

Вот что получилось Но в companyM._mode прилетает null, так что сравнивать нечего.

вот, метод валидации

[AcceptVerbs("Get", "Post")]
        public IActionResult CheckName(string name, Company companyM)
        {
            List<Company> companies = _context.Companies.ToList();
            // var companies = _context.Companies.Include(c => c._Company);
            if (companyM._mode != "Edit")
            {
                foreach (var company in companies)
                {
                    if (company.Name == name)
                    {
                        return Json(false);
                    }
                }
            }

            return Json(true);
        }

Вот модель

public class Company
    {
        public int Id { get; set; }
        [Required]
        [StringLength(15, MinimumLength = 3)]
        [Remote(action: "CheckName", controller: "Validation", ErrorMessage = "Эй! Уф, нэ пеши сюда ето имя:-[ Оно уже есь же, эсь жи!!")]
        [Display(Name = "Название компании")]
        public string Name { get; set; }
        [EmailAddress]
        [Display(Name = "Почта компании")]
        public string _emailCompany { get; set; }
        //[Range(typeof(DateTime), "01/01/1975 01:01", "01/01/2019 01:01")]
        [DataType(DataType.DateTime)]
        [Display(Name = "Дата создания компании")]
        public DateTime _dataCreateCompany { get; set; }

        public int? _CompanyId { get; set; }
        public Company _Company { get; set; }
        public string _mode { get; set; }
        public IEnumerable<Company> CompaniesEnumerable { get; set; }
        public IEnumerable<Phone> Phones { get; set; }
    }

Вот представление Edit

@model Company
@{
    ViewData["Title"] = "Edit";
}
<h2>Edit</h2>
<h4>Company</h4>
<hr/>
@using (Html.BeginForm("Edit", "Company", FormMethod.Post))
{
    @Html.HiddenFor(x => x._mode, "Edit")
    <div class="row">
        <div class="col-md-4">
            <form asp-action="Edit">
                <div asp-validation-summary="ModelOnly" class="text-danger"></div>
                <input type="hidden" asp-for="Id"/>
                <div class="form-group">
                    <label asp-for="Name" class="control-label"></label>
                    <input asp-for="Name" class="form-control"/>
                    <span asp-validation-for="Name" class="text-danger"></span>
                </div>
                <div class="form-group">
                    <label asp-for="_emailCompany" class="control-label"></label>
                    <input asp-for="_emailCompany" class="form-control"/>
                    <span asp-validation-for="_emailCompany" class="text-danger"></span>
                </div>
                <div class="form-group">
                    <label asp-for="_dataCreateCompany" class="control-label"></label>
                    <input asp-for="_dataCreateCompany" class="form-control"/>
                    <span asp-validation-for="_dataCreateCompany" class="text-danger"></span>
                </div>
                <div class="form-group">
                    <label asp-for="_CompanyId" class="control-label"></label>
                    <select asp-for="_CompanyId" class="form-control" asp-items="ViewBag._CompanyId"></select>
                    <span asp-validation-for="_CompanyId" class="text-danger"></span>
                </div>
                <div class="form-group">
                    <input type="submit" type="hidden" name="Mode" value="Save" class="btn btn-default"/>
                </div>
            </form>
        </div>
    </div>
    <div>
        <a asp-action="Index">Back to List</a>
    </div> 
}

@section Scripts {
    @{ await Html.RenderPartialAsync("_ValidationScriptsPartial"); }
}

Вот представление Create

@model MyFirstMVC.Models.Company
@{
    ViewData["Title"] = "Create";
}
<h2>Create</h2>
<h4>Category</h4>
<hr/>
@using (Html.BeginForm("Create", "Company", FormMethod.Post))
{
    @Html.HiddenFor(x => x._mode, "Create")
    <div class="row">
        <div class="col-md-4">
            <form asp-action="Create">
                <div asp-validation-summary="ModelOnly" class="text-danger"></div>
                <div class="form-group">
                    <label asp-for="Name" class="control-label"></label>
                    <input asp-for="Name" class="form-control"/>
                    <span asp-validation-for="Name" class="text-danger"></span>
                </div>
                @* Email *@
                <div class="form-group">
                    <label asp-for="_emailCompany" class="control-label"></label>
                    <input asp-for="_emailCompany" class="form-control"/>
                    <span asp-validation-for="_emailCompany" class="text-danger"></span>
                </div>
                @* Data *@
                <div class="form-group">
                    <label asp-for="_dataCreateCompany"  class="control-label"></label>
                    <input asp-for="_dataCreateCompany" class="form-control"/>
                    <span asp-validation-for="_dataCreateCompany" class="text-danger"></span>
                </div>
                <div class="form-group">
                    <input type="submit" type="hidden" name="Mode" value="Create" class="btn btn-default"/>
                </div>
            </form>
        </div>
    </div>
    <div>
        <a asp-action="Index">Back to List</a>
    </div>
}
@section Scripts {
    @{ await Html.RenderPartialAsync("_ValidationScriptsPartial"); }
}
Answer 1

Вообще-то самый правильный вариант — сделать две разных модели (одну для Create, другую - для Edit) и оставить атрибут [Remote] только для Create.

Но если же очень хочется оставить одну модель — то можете поправить свой action CheckName, выполняющий проверку, чтобы он для метода Edit возвращал всегда true (А для Create - отрабатывайте логику как есть).

Как в этом случае узнать, какой метод работает? Просто добавьте в модель ещё одно свойство Mode:

public class SomeModel
{
    ...
    [Required]
    [StringLength(15, MinimumLength = 3)]
    [Remote(action: "CheckName", controller: "Validation", ErrorMessage = "Эй! Уф, нэ пеши сюда ето имя:-[ Оно уже есь же, эсь жи!!")]
    [Display(Name = "Название компании")]
    public string Name { get; set; }
    ...
    public string Model { get; set; }
    ...
}

И в представлении Create заполняйте его значением Create:

@model SomeModel
<h1>Create</h1>
@using (Html.BeginForm("Create", "Enity", FormMethod.Post))
{
    @Html.HiddenFor(x => x.Mode, "Create")
    ...
}

А в представлении Edit — значением Edit:

@model SomeModel
<h1>Edit</h1>
@using (Html.BeginForm("Edit", "Enity", FormMethod.Post))
{
    @Html.HiddenFor(x => x.Mode, "Edit")
    ...
}

Разумеется, поле должно быть невидимым (hidden) input'ом, вариант html если вы форму генерируете вручную:

<input type="hidden" value="Create" name="Mode">

Ну и в вашем action на валидацию пишете:

if(model.Mode == "Create} { ... }

Ну или полностью:

[AcceptVerbs("Get", "Post")]
public IActionResult CheckName(string name, Company companyM, string mode)
{
    List<Company> companies = _context.Companies.ToList();
    // var companies = _context.Companies.Include(c => c._Company);
    if (mode == "Edit")
    {
        // Не проверяем для Edit
        return Json(true);
    }
    // Проверяем для Create
    // NB: Это выражение можно заменить на LINQ
    foreach (var company in companies)
    {
        if (company.Name == name)
        {
            return Json(false);
        }
    }
    return Json(true);
}

Я на вашем месте предпочёл бы первый вариант. Хорошее приложение - это приложение, которое легко поддерживать. Во втором варианте у вас усложняется логика на стороне контроллера, а в первом варианте не усложняется. В первом варианте у вас один класс несёт одну отвественность, а во втором случае две.

PS. Я часто сталкиваюсь с людьми, которые боятся продублировать лишнюю строчку кода и не понимают, что в данном случае это дублирование кода является хорошим дублированием, которое упрощает жизнь.

Давайте вспомним, почему вообще настоятельно рекомендуют избегать дублирования кода и считают плохой практикой? Вот допустим, код который делает "создание сущности" и код, который делает "редактирование сущности".

Допустим, они похожи, но чуть-чуть различаются. Волевым усилием, потратив полчаса времени мы придумываем, как написать этот максимально одинаковым способом и восторгаясь закрываем IDE. Здорово? Нет!

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

В данном случае нет необходимости придумывать, как объединять код. У него просто разная ответственность. Ввспоминаем Single Responsibility Principle: у каждого класса должна быть только одна причина для изменения. Если класс отвечает и за создание и за редактирование - этот класс нарушает SPR.

Любое дублирование кода в данном случае является случайным совпадением, отражающим логику того, что ваши модели (ViewModel, Dto) отражают одну и ту же единственную сущность (Entity, Model).

Приведу примеры.

У меня есть Entity "Пользователь" (User), у которой есть поле "Пароль" (Password). И у меня есть модель создания пользователя (с полями UserName, Email, Password, ConfirmationPassword), смены логина (c полем UserName) и модель для сброса пароля (с полями UserId, OldPassword, NewPassword, ConfirmationNewPassword). Наборы полей примерно одинаковые во всех случаях (это всегда подмножества полей сущности), иногда дублируются (Password + Confirmation), но ведь вам из-за этой похожести не приходит в голову "А давайте мы создадим ОДНУ МОДЕЛЬ НА ВСЁ!!", верно? Это очень разные действия.

И у меня в реальных приложениях много подобных примеров. Например, при создании сущности я могу спросить только 2-3 поля, хотя в модели на редактирование полей будет два десятка. Зачем? Чтобы упростить процесс создания. Например, при редактировании заказа есть поле "статус", но при создании оно не нужно - все заказы создаются в статусе New. Зачем тогда выводить его на экран, чтобы оно только место занимало и пугало пользователя "смотри, какая длинная форма, у нас не абы какое приложение - а настоящий энтерпрайз!"

Также помимо моделей Create и Edit (действительно, часто во многом совпадающих) мне приходится делать модель для Clone - и это тоже отдельная модель, которая немного похожа на Create, а немного - на Edit.

Так что не следуйте слепо рекомендациям, а понимайте для чего они сделаны и применимо ли это в конкретном случае.

READ ALSO
Как отрисовать данную ветку интерфейса WPF

Как отрисовать данную ветку интерфейса WPF

Имеется данный кусочек интерфейса, нужно его отрисовать, но не знаю как, подскажитеБыл бы благодарен если ещё и с объяснением, сфера новая,...

161
PHP Конвертер кукисов с netscape в json

PHP Конвертер кукисов с netscape в json

Нашел скрипт на просторах сети, конвертер cookies файлов формата Netscape в формат JSONНо почему-то у меня вместо JSON Cookies в файл cookies

490
Отображается шапка с группы в вк

Отображается шапка с группы в вк

При использование виджета vk отображается и часть шапки группы

166
Проблема передачи файла на базу данных

Проблема передачи файла на базу данных

у меня возникла проблема и она заключается в том, что при передачи изображении на базу данных, где находится ее поле пишет слово Array - массив...

172