Мне было интересно, можно ли отключить атрибут обязательной проверки в определенных действиях контроллера. Мне это интересно, потому что в одной из моих форм редактирования я не требую, чтобы пользователь вводил значения для полей, которые они уже указали ранее. Однако затем я реализую логику, согласно которой при вводе значения используется специальная логика для обновления модели, например хеширование значения и т. Д.
Есть предложения о том, как обойти эту проблему?
РЕДАКТИРОВАТЬ:
И да, проверка клиента - это проблема, поскольку она не позволит им отправить форму без ввода значения.
c#
asp.net-mvc
asp.net-mvc-3
data-annotations
Алекс Хоуп О'Коннор
источник
источник
RequiredAttr
полностью удалить его и при необходимости выполнить проверку на стороне сервера . Но это будет сложно для клиентаОтветы:
Эту проблему легко решить, используя модели представления. Модели представления - это классы, специально адаптированные к потребностям данного представления. Так, например, в вашем случае у вас могут быть следующие модели представления:
public UpdateViewView { [Required] public string Id { get; set; } ... some other properties } public class InsertViewModel { public string Id { get; set; } ... some other properties }
которые будут использоваться в соответствующих действиях контроллера:
[HttpPost] public ActionResult Update(UpdateViewView model) { ... } [HttpPost] public ActionResult Insert(InsertViewModel model) { ... }
источник
Update(FormCollection collection)
, по крайней мере, никогда. Я всегда определить и использовать конкретную модель представления:Update(UpdateViewView model)
.Insert
. Спасибо за указание на это.Если вы просто хотите отключить проверку для одного поля на стороне клиента, вы можете переопределить атрибуты проверки следующим образом:
@Html.TextBoxFor(model => model.SomeValue, new Dictionary<string, object> { { "data-val", false }})
источник
@Html.TexBoxFor(model => model.SomeValue, new { data_val = false })
- легче читать ИМО.$(".search select").attr('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]
атрибут в базовом классе, вам не нужно переопределять его в своемUpdateModel
.И вы по-прежнему можете использовать эти классы таким же образом:
[HttpPost] public ActionResult Update(UpdateModel model) { ... } [HttpPost] public ActionResult Insert(InsertModel model) { ... }
источник
Вы можете удалить все проверки свойства с помощью следующих действий в вашем контроллере.
Комментарий @ Ian относительно MVC5
Еще возможно следующее
ModelState.Remove("PropertyNameInModel");
Немного раздражает, что вы теряете статическую типизацию с обновленным API. Вы можете добиться чего-то похожего на старый способ, создав экземпляр помощника HTML и используя методы NameExtensions .
источник
ModelState
который бы соответствовал этой подписи. По крайней мере, не в MVC 5.Клиентская сторона Для отключения проверки формы ниже приведены несколько вариантов, основанных на моем исследовании. Надеюсь, один из них подойдет вам.
Опция 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 динамически.
источник
Лично я склонен использовать подход, который Дарин Димитров продемонстрировал в своем решении. Это освобождает вас, чтобы иметь возможность использовать подход аннотации данных с проверкой И иметь отдельные атрибуты данных для каждой ViewModel, соответствующие поставленной задаче. Чтобы свести к минимуму объем работы по копированию между моделью и моделью просмотра, вам следует взглянуть на AutoMapper или ValueInjecter . У обоих есть свои сильные стороны, поэтому проверьте их обоих.
Другой возможный подход для вас - получить вашу модель представления или модель из IValidatableObject. Это дает вам возможность реализовать функцию Validate. При проверке вы можете вернуть либо список элементов ValidationResult, либо выдать возврат доходности для каждой проблемы, обнаруженной при проверке.
ValidationResult состоит из сообщения об ошибке и списка строк с именами полей. Сообщения об ошибках будут отображаться рядом с полями ввода.
public IEnumerable<ValidationResult> 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; }
источник
Я считаю, что самый чистый способ здесь отключить проверку на стороне клиента, и на стороне сервера вам нужно будет:
Кажется, что даже настраиваемая модель представления здесь не решит проблему, потому что количество полей с предварительным ответом может варьироваться. Если это не так, то пользовательская модель представления действительно может быть самым простым способом, но с помощью описанной выше техники вы можете обойти свои проблемы с проверкой.
источник
это был чей-то ответ в комментариях ... но это должен быть настоящий ответ:
$("#SomeValue").removeAttr("data-val-required")
протестирован на MVC 6 с полем, имеющим
[Required]
атрибутомответ украден с https://stackoverflow.com/users/73382/rob выше
источник
У меня возникла эта проблема, когда я создавал представление редактирования для своей модели, и я хочу обновить только одно поле.
Мое решение для простейшего способа - поместить два поля, используя:
Комментарии - это поле, которое я обновляю только в режиме редактирования, у которого нет обязательного атрибута.
Сущность ASP.NET MVC 3
источник
AFAIK вы не можете удалить атрибут во время выполнения, а только изменить их значения (например, только для чтения, true / false), посмотрите здесь что-то подобное . В качестве еще одного способа делать то, что вы хотите, не вмешиваясь в атрибуты, я выберу ViewModel для вашего конкретного действия, чтобы вы могли вставить всю логику, не нарушая логику, необходимую для других контроллеров. Если вы попытаетесь получить какой-то мастер (многоступенчатую форму), вы можете вместо этого сериализовать уже скомпилированные поля и с помощью TempData переносить их по своим шагам. (для помощи в сериализации десериализации вы можете использовать фьючерсы MVC )
источник
То, что сказал @Darin, я тоже рекомендую. Однако я бы добавил к нему (и в ответ на один из комментариев), что вы фактически также можете использовать этот метод для примитивных типов, таких как bit, bool, даже структур, таких как Guid, просто сделав их допускающими значение NULL. Как только вы это сделаете,
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;
источник
Я искал решение, в котором я мог бы использовать ту же модель для вставки и обновления в веб-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. В этом переопределении я фильтрую требуемые валидаторы модели. А теперь класс IgnoreRequiredOrDefaultBodyModelValidator и класс атрибута 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<HttpActionBinding, bool> _ignoreRequiredValidationByActionBindingCache; static IgnoreRequiredOrDefaultBodyModelValidator() { _ignoreRequiredValidationByActionBindingCache = new ConcurrentDictionary<HttpActionBinding, bool>(); } protected override bool ShallowValidate(ModelMetadata metadata, BodyModelValidatorContext validationContext, object container, IEnumerable<ModelValidator> 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<IgnoreRequiredValidationsAttribute>(false) != null; } #endregion } [AttributeUsage(AttributeTargets.Method, Inherited = true)] public class IgnoreRequiredValidationsAttribute : Attribute { } }
Источники:
string debug = new StackTrace().ToString()
чтобы узнать, кто занимается проверкой модели.источник
Если вы не хотите использовать другую ViewModel, вы можете отключить проверки клиентов в представлении, а также удалить проверки на сервере для тех свойств, которые вы хотите игнорировать. Пожалуйста, проверьте этот ответ для более глубокого объяснения https://stackoverflow.com/a/15248790/1128216
источник
В моем случае одна и та же Модель использовалась на многих страницах для повторного использования. Итак, я создал настраиваемый атрибут, который проверяет исключения.
public class ValidateAttribute : ActionFilterAttribute { public string Exclude { get; set; } public string Base { get; set; } public override void OnActionExecuting(HttpActionContext actionContext) { if (!string.IsNullOrWhiteSpace(this.Exclude)) { string[] excludes = this.Exclude.Split(','); foreach (var exclude in excludes) { actionContext.ModelState.Remove(Base + "." + exclude); } } if (actionContext.ModelState.IsValid == false) { var mediaType = new MediaTypeHeaderValue("application/json"); var error = actionContext.ModelState; actionContext.Response = actionContext.Request.CreateResponse(HttpStatusCode.OK, error.Keys, mediaType); } } }
и в вашем контроллере
[Validate(Base= "person",Exclude ="Age,Name")] public async Task<IHttpActionResult> Save(User person) { //do something }
Скажите, что модель
public class User { public int Id { get; set; } [Required] public string Name { get; set; } [Range(18,99)] public string Age { get; set; } [MaxLength(250)] public string Address { get; set; } }
источник
Да, можно отключить обязательный атрибут. Создайте свой собственный атрибут настраиваемого класса (образец кода с именем ChangeableRequired) для экстента из RequiredAtribute, добавьте свойство Disabled и переопределите метод IsValid, чтобы проверить, не отключен ли он. Используйте отражение, чтобы установить отключенное свойство, например:
Пользовательский атрибут:
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;} .... }
где вам нужно отключить отражение использования свойства, чтобы установить его:
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: приведенная выше проверка будет отключена, пока ваш экземпляр объекта жив \ активен ...
источник