Отключить Обязательный атрибут проверки при определенных обстоятельствах

Мне было интересно, можно ли отключить атрибут Required validation в определенных действиях controllerа. Мне интересно это, потому что в одной из моих форм редактирования я не требую, чтобы пользователь вводил значения для полей, которые они уже указали ранее. Однако я тогда реализую логику, что, когда они вводят значение, она использует некоторую специальную логику для обновления модели, например, hashирование значения и т. Д.

Любые предложения по решению этой проблемы?

РЕДАКТИРОВАТЬ:
И да, проверка клиента является проблемой здесь, так как она не позволит им отправить форму без ввода значения.

Эту проблему можно легко решить, используя модели просмотра. Модели просмотра – это classы, специально предназначенные для нужд данного вида. Так, например, в вашем случае у вас могут быть следующие модели представлений:

 public UpdateViewView { [Required] public string Id { get; set; } ... some other properties } public class InsertViewModel { public string Id { get; set; } ... some other properties } 

которые будут использоваться в их соответствующих действиях controllerа:

 [HttpPost] public ActionResult Update(UpdateViewView model) { ... } [HttpPost] public ActionResult Insert(InsertViewModel model) { ... } 

Если вы просто хотите отключить проверку для одного поля на стороне клиента, вы можете переопределить атрибуты проверки следующим образом:

 @Html.TexBoxFor(model => model.SomeValue, new Dictionary { { "data-val", false }}) 

Я знаю, что на этот вопрос уже давно дан ответ, и принятый ответ действительно выполнит эту работу. Но меня беспокоит одна вещь: копировать 2 модели только для того, чтобы отключить проверку.

Вот мое предложение:

 public class InsertModel { [Display(...)] public virtual string ID { get; set; } ...Other properties } public class UpdateModel : InsertModel { [Required] public override string ID { get { return base.ID; } set { base.ID = value; } } } 

Таким образом, вам не нужно беспокоиться о проверке на стороне клиента / сервера, структура будет вести себя так, как предполагается. Кроме того, если вы определяете атрибут [Display] в базовом classе, вам не нужно переопределять его в UpdateModel .

И вы все равно можете использовать эти classы одинаково:

 [HttpPost] public ActionResult Update(UpdateModel model) { ... } [HttpPost] public ActionResult Insert(InsertModel model) { ... } 

Лично я хотел бы использовать подход, предложенный Дарином Димитровым в его решении. Это освобождает вас от возможности использовать подход annotations данных с проверкой и иметь отдельные атрибуты данных для каждого ViewModel, соответствующего задаче. Чтобы свести к минимуму объем работы для копирования между моделью и viewmodel, вы должны посмотреть AutoMapper или ValueInjecter . Оба имеют свои индивидуальные сильные стороны, поэтому проверьте их обоих.

Другим возможным подходом для вас было бы получение вашей модели представления или модели из документа IValidatableObject. Это дает вам возможность реализовать функцию Validate. В validate вы можете возвращать элементы списка ValidationResult или выдавать возврат доходности для каждой проблемы, которую вы обнаруживаете при проверке.

ValidationResult состоит из сообщения об ошибке и списка строк с именами полей. Сообщения об ошибках будут отображаться в месте рядом с полем ввода.

 public IEnumerable Validate(ValidationContext validationContext) { if( NumberField < 0 ) { yield return new ValidationResult( "Don't input a negative number", new[] { "NumberField" } ); } if( NumberField > 100 ) { yield return new ValidationResult( "Don't input a number > 100", new[] { "NumberField" } ); } yield break; } 

Сторона клиента. Для отключения проверки для формы несколько вариантов, основанных на моих исследованиях, приведены ниже. Один из них, надеюсь, сработает для вас.

Опция 1

Я предпочитаю это, и это отлично работает для меня.

 (function ($) { $.fn.turnOffValidation = function (form) { var settings = form.validate().settings; for (var ruleIndex in settings.rules) { delete settings.rules[ruleIndex]; } }; })(jQuery); 

и ссылаться на него как

 $('#btn').click(function () { $(this).turnOffValidation(jQuery('#myForm')); }); 

Вариант 2

 $('your selector here').data('val', false); $("form").removeData("validator"); $("form").removeData("unobtrusiveValidation"); $.validator.unobtrusive.parse("form"); 

Вариант 3

 var settings = $.data($('#myForm').get(0), 'validator').settings; settings.ignore = ".input"; 

Вариант 4

  $("form").get(0).submit(); jQuery('#createForm').unbind('submit').submit(); 

Вариант 5

 $('input selector').each(function () { $(this).rules('remove'); }); 

Серверная сторона

Создайте атрибут и пометьте свой метод действия этим атрибутом. Настройте это, чтобы адаптироваться к вашим конкретным потребностям.

 [AttributeUsage(AttributeTargets.All)] public class IgnoreValidationAttribute : ActionFilterAttribute { public override void OnActionExecuting(ActionExecutingContext filterContext) { var modelState = filterContext.Controller.ViewData.ModelState; foreach (var modelValue in modelState.Values) { modelValue.Errors.Clear(); } } } 

Здесь был описан лучший подход. Динамически активировать / отключить проверку на стороне сервера mvc

Вы можете удалить всю проверку с помощью свойства со следующим действием в вашем controllerе.

 ModelState.Remove(x => x.SomeProperty); 

@ Комментарий Яна относительно MVC5

Возможно все еще

 ModelState.Remove("PropertyNameInModel"); 

Немного раздражает то, что вы теряете статическую типизацию с обновленным API. Вы могли бы достичь чего-то похожего на старый способ, создав экземпляр HTML-помощника и используя методы NameExtensions .

Самый чистый способ, который, как я полагаю, приведет к отключению проверки на стороне клиента, и на стороне сервера вам потребуется:

  1. ModelState [“SomeField”]. Errors.Clear (в вашем controllerе или создать фильтр действий для удаления ошибок до выполнения кода controllerа)
  2. Добавьте ModelState.AddModelError из кода вашего controllerа, когда вы обнаружите нарушение обнаруженных проблем.

Кажется, что даже пользовательская модель просмотра здесь не решит проблему, потому что количество полей «предварительно ответил» может отличаться. Если они не будут тогда, пользовательская модель просмотра может быть самым простым способом, но с использованием вышеупомянутой техники вы можете обойти свои проблемы с проверками.

это был чужой ответ в комментариях … но это должен быть реальный ответ:

$("#SomeValue").removeAttr("data-val-required")

проверен на MVC 6 с полем, имеющим атрибут [Required]

ответ украден из https://stackoverflow.com/users/73382/rob выше

У меня возникла эта проблема, когда я создаю Edit View для моей модели, и я хочу обновить только одно поле.

Мое решение для простейшего способа заключается в том, чтобы использовать два поля:

  <%: Html.HiddenFor(model => model.ID) %> <%: Html.HiddenFor(model => model.Name)%> <%: Html.HiddenFor(model => model.Content)%> <%: Html.TextAreaFor(model => model.Comments)%> 

Комментарии – это поле, которое я только обновляю в Edit View, который не имеет обязательного атрибута.

ASP.NET MVC 3 Entity

AFAIK вы не можете удалить атрибут во время выполнения, но только изменить их значения (то есть: readonly true / false) посмотреть здесь на что-то подобное . В качестве другого способа сделать то, что вы хотите, не вникая в атрибуты, я пойду с ViewModel для вашего конкретного действия, чтобы вы могли вставить всю логику, не нарушая логику, требуемую другими controllerами. Если вы попытаетесь получить какой-то мастер (многоступенчатая форма), вы можете вместо этого сериализовать уже скомпилированные поля, а с помощью TempData вывести их по шагам. (для помощи в сериализации десериализации вы можете использовать фьючерсы MVC )

То, что сказал @Darin, я бы рекомендовал. Однако я бы добавил к нему (и в ответ на один из комментариев), что на самом деле вы также можете использовать этот метод для примитивных типов, таких как бит, bool, даже структуры типа Guid, просто делая их обнуляемыми. Как только вы это сделаете, атрибут Required функционирует так, как ожидалось.

 public UpdateViewView { [Required] public Guid? Id { get; set; } [Required] public string Name { get; set; } [Required] public int? Age { get; set; } [Required] public bool? IsApproved { get; set; } //... some other properties } 

С MVC 5 это можно легко достичь, добавив это в свой global.asax .

 DataAnnotationsModelValidatorProvider.AddImplicitRequiredAttributeForValueTypes = false; 

Я искал решение, в котором я могу использовать ту же модель для вставки и обновления в web api. В моей ситуации это всегда содержание тела. [Requiered] должны быть пропущены, если это метод обновления. В моем решении вы поместите атрибут [IgnoreRequiredValidations] над этим методом. Это выглядит так:

 public class WebServiceController : ApiController { [HttpPost] public IHttpActionResult Insert(SameModel model) { ... } [HttpPut] [IgnoreRequiredValidations] public IHttpActionResult Update(SameModel model) { ... } ... 

Что еще нужно сделать? Собственный BodyModelValidator должен быть создан и добавлен при запуске. Это находится в HttpConfiguration и выглядит так: config.Services.Replace(typeof(IBodyModelValidator), new IgnoreRequiredOrDefaultBodyModelValidator());

 using Owin; using your_namespace.Web.Http.Validation; [assembly: OwinStartup(typeof(your_namespace.Startup))] namespace your_namespace { public class Startup { public void Configuration(IAppBuilder app) { Configuration(app, new HttpConfiguration()); } public void Configuration(IAppBuilder app, HttpConfiguration config) { config.Services.Replace(typeof(IBodyModelValidator), new IgnoreRequiredOrDefaultBodyModelValidator()); } ... 

Мой собственный BodyModelValidator получен из DefaultBodyModelValidator. И я понимаю, что мне пришлось переопределить метод «ShallowValidate». В этом переопределении я фильтрую валидаторы модели requierd. И теперь class IgnoreRequiredOrDefaultBodyModelValidator и class атрибута IgnoreRequiredValidations:

 using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.Linq; using System.Reflection; using System.Web.Http.Controllers; using System.Web.Http.Metadata; using System.Web.Http.Validation; namespace your_namespace.Web.Http.Validation { public class IgnoreRequiredOrDefaultBodyModelValidator : DefaultBodyModelValidator { private static ConcurrentDictionary _ignoreRequiredValidationByActionBindingCache; static IgnoreRequiredOrDefaultBodyModelValidator() { _ignoreRequiredValidationByActionBindingCache = new ConcurrentDictionary(); } protected override bool ShallowValidate(ModelMetadata metadata, BodyModelValidatorContext validationContext, object container, IEnumerable validators) { var actionContext = validationContext.ActionContext; if (RequiredValidationsIsIgnored(actionContext.ActionDescriptor.ActionBinding)) validators = validators.Where(v => !v.IsRequired); return base.ShallowValidate(metadata, validationContext, container, validators); } #region RequiredValidationsIsIgnored private bool RequiredValidationsIsIgnored(HttpActionBinding actionBinding) { bool ignore; if (!_ignoreRequiredValidationByActionBindingCache.TryGetValue(actionBinding, out ignore)) _ignoreRequiredValidationByActionBindingCache.TryAdd(actionBinding, ignore = RequiredValidationsIsIgnored(actionBinding.ActionDescriptor as ReflectedHttpActionDescriptor)); return ignore; } private bool RequiredValidationsIsIgnored(ReflectedHttpActionDescriptor actionDescriptor) { if (actionDescriptor == null) return false; return actionDescriptor.MethodInfo.GetCustomAttribute(false) != null; } #endregion } [AttributeUsage(AttributeTargets.Method, Inherited = true)] public class IgnoreRequiredValidationsAttribute : Attribute { } } 

Источники:

Если вы не хотите использовать другой ViewModel, вы можете отключить проверку клиента в представлении, а также удалить проверки на сервере для тех свойств, которые вы хотите игнорировать. Пожалуйста, проверьте этот ответ для более глубокого объяснения. https://stackoverflow.com/a/15248790/1128216

Да, можно отключить Обязательный атрибут. Создайте свой собственный атрибут classа (образец кода под названием ChangeableRequired) до степени от RequiredAtribute и добавьте свойство Disabled и переопределите метод IsValid, чтобы проверить, не разнесено ли оно. Используйте рефлексию, чтобы установить отключенную poperty, например:

Пользовательский атрибут:

 namespace System.ComponentModel.DataAnnotations { public class ChangeableRequired : RequiredAttribute { public bool Disabled { get; set; } public override bool IsValid(object value) { if (Disabled) { return true; } return base.IsValid(value); } } } 

Обновите свойство, чтобы использовать новый пользовательский атрибут:

  class Forex { .... [ChangeableRequired] public decimal? ExchangeRate {get;set;} .... } 

где вам нужно отключить reflection использования свойства, чтобы установить его:

 Forex forex = new Forex(); // Get Property Descriptor from instance with the Property name PropertyDescriptor descriptor = TypeDescriptor.GetProperties(forex.GetType())["ExchangeRate"]; //Search for Attribute ChangeableRequired attrib = (ChangeableRequired)descriptor.Attributes[typeof(ChangeableRequired)]; // Set Attribute to true to Disable attrib.Disabled = true; 

Это приятно и чисто?

NB: проверка правильности выше будет отключена, пока экземпляр объекта активен \ активно …

  • Использование String Format для отображения десятичной до 2-х мест или простого целого
  • Хорошие инструменты для создания анализатора / анализатора C / C ++
  • Как я могу перебирать все флажки в форме?
  • C ++ / Win32: Как дождаться завершения отложенного удаления?
  • MVC Как отобразить изображение байтового массива из модели
  • Как получить список всех принтеров на компьютере
  • Как получить IP-адрес сервера, на котором работает мое приложение C #?
  • Как сделать .lib-файл, когда есть .dll-файл и заголовочный файл
  • Служба проверки подлинности с использованием WCF
  • Почему бросание 2 исключений в строке не генерирует недопустимый код предупреждения?
  • Заменить вектор, используя вектор индексов
  • Давайте будем гением компьютера.