在某些情况下禁用必需的validation属性
我想知道是否可以在某些控制器操作中禁用Requiredvalidation属性。 我想知道这一点,因为在我的编辑forms之一,我不需要用户input他们以前已经指定的字段的值。 然而,我然后实现逻辑,当他们input一个值时,它使用一些特殊的逻辑来更新模型,如哈希值等
任何有关如何解决这个问题的build议?
编辑:
而且客户validation在这里是一个问题,因为它不允许他们提交表单而不input值。
这个问题可以通过使用视图模型来解决。 视图模型是专门针对特定视图的需求量身定制的类。 所以例如在你的情况下,你可以有以下的视图模型:
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) { ... }
如果您只想禁用客户端单个字段的validation,那么您可以覆盖validation属性,如下所示:
@Html.TexBoxFor(model => model.SomeValue, new Dictionary<string, object> { { "data-val", false }})
我知道这个问题很久以前就已经有了答案,接受的答案实际上是做这个工作的。 但有一件事情让我困扰:不得不复制2个模型来禁用validation。
这是我的build议:
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; } } }
这样,您就不必担心客户端/服务器端的validation,框架将按照预期的方式运行。 另外,如果您在基类中定义了[Display]
属性,则不必在UpdateModel
重新定义它。
而且你仍然可以用同样的方法使用这些类:
[HttpPost] public ActionResult Update(UpdateModel model) { ... } [HttpPost] public ActionResult Insert(InsertModel model) { ... }
就我个人而言,我倾向于使用达林·季米特洛夫(Darin Dimitrov)在解决scheme中performance出的方法 这使您能够使用数据注释方法进行validation,并在每个ViewModel上具有与当前任务相对应的单独数据属性。 要最大限度地减less模型和视图模型之间的复制工作量,您应该查看AutoMapper或ValueInjecter 。 两者都有自己的优点,所以检查他们两个。
另一种可能的方法是从IValidatableObject派生你的视图模型或模型。 这给你select实现一个函数validation。 在validation中,您可以返回一个ValidationResult元素列表,或者为您在validation中检测到的每个问题发出一个收益回报。
ValidationResult由一个错误消息和一个带有字段名的string列表组成。 错误消息将显示在靠近input字段的位置。
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; }
客户端为了禁用表单validation,下面给出了基于我的研究的多个选项。 其中一人会希望为你工作。
选项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'); });
服务器端
创build一个属性并使用该属性标记您的操作方法。 自定义此以适应您的特定需求。
[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(); } } }
在这里描述了一个更好的方法dynamic地启用/禁用mvc服务器端validation
您可以使用控制器操作中的以下内容删除属性中的所有validation。
ModelState.Remove<ViewModel>(x => x.SomeProperty);
@ Ian对MVC5 的评论
以下依然是可能的
ModelState.Remove("PropertyNameInModel");
有点烦人,你失去了与更新的API的静态types。 您可以通过创build一个HTML助手实例并使用NameExtensions方法来实现与旧方法类似的操作。
我相信这里最干净的方法是禁用你的客户端validation,在服务器端你将需要:
- ModelState [“SomeField”]。Errors.Clear(在您的控制器中或创build一个操作filter,以在执行控制器代码之前删除错误)
- 当您检测到违反检测到的问题时,从您的控制器代码中添加ModelState.AddModelError。
似乎甚至一个自定义视图模型在这里不会解决这个问题,因为这些“预先回答”字段的数量可能会有所不同。 如果他们不那么自定义视图模型可能确实是最简单的方法,但使用上述技术,你可以解决你的validation问题。
这是别人在评论中的回答…但它应该是一个真正的答案:
$("#SomeValue").removeAttr("data-val-required")
在MVC 6上使用具有[Required]
属性的字段进行testing
当我为我的模型创build编辑视图时,我遇到了这个问题,我只想更新一个字段。
我最简单的解决方法是使用两个字段:
<%: Html.HiddenFor(model => model.ID) %> <%: Html.HiddenFor(model => model.Name)%> <%: Html.HiddenFor(model => model.Content)%> <%: Html.TextAreaFor(model => model.Comments)%>
注释是我只在编辑视图中更新的字段,没有必需的属性。
ASP.NET MVC 3实体
AFAIK你不能删除属性在运行时,但只改变它们的值(即:只读true / false) 在这里寻找类似的东西 。 作为另一种做你想要什么而不搞乱属性的方式,我将使用一个ViewModel来进行特定的动作,这样你就可以插入所有的逻辑而不会破坏其他控制器所需要的逻辑。 如果您尝试获取某种types的向导(多步forms),则可以序列化已编译的字段,并使用TempData将它们沿着您的步骤引入。 (为了帮助序列化反序列化,你可以使用MVC期货 )
@达琳所说的是我所推荐的。 不过,我会join(并回应其中一个评论),你实际上也可以使用这种方法的原始types,如比特,布尔,甚至像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 }
如果您不想使用其他ViewModel,则可以禁用视图上的客户端validation,也可以在服务器上删除要忽略的属性的validation。 请检查这个答案的更深入的解释https://stackoverflow.com/a/15248790/1128216
是的,可以禁用必需的属性。 创build您自己的自定义类属性(示例代码称为ChangeableRequired)从RequiredAtribute范围,并添加一个禁用的属性,并重写IsValid方法来检查它是否disbaled。 使用reflection设置禁用的属性,如下所示:
自定义属性:
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;
这感觉很好,干净?
注意:上面的validation将被禁用,而您的对象实例活着\活跃…