我想知道是否可以在某些控制器操作中禁用Required validation属性。我想知道这是因为在我的一个编辑表单中,我不需要用户输入他们之前已经指定的字段的值。然而,我然后实现逻辑,当它们输入值时,它使用一些特殊的逻辑来更新模型,例如散列值等。
有关如何解决此问题的任何消息?
编辑:
是的,客户端验证是一个问题,因为它不允许他们在不输入值的情况下提交表单。
答案 0 :(得分:72)
使用视图模型可以轻松解决此问题。视图模型是专门针对给定视图的需求而定制的类。例如,在您的情况下,您可以使用以下视图模型:
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)
{
...
}
答案 1 :(得分:54)
如果您只想在客户端禁用单个字段的验证,则可以按如下方式覆盖验证属性:
@Html.TexBoxFor(model => model.SomeValue,
new Dictionary<string, object> { { "data-val", false }})
答案 2 :(得分:39)
我知道很久以前这个问题已得到解答,接受的答案实际上会完成。但是有一件事困扰着我:只需要复制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)
{
...
}
答案 3 :(得分:18)
您可以在控制器操作中使用以下内容删除属性的所有验证。
ModelState.Remove<ViewModel>(x => x.SomeProperty);
@Ian's关于MVC5的评论
以下仍然可能
ModelState.Remove("PropertyNameInModel");
有点烦人的是你丢失了使用更新的API的静态类型。您可以通过创建HTML帮助程序实例并使用NameExtensions Methods来实现与旧方法类似的操作。
答案 4 :(得分:14)
我个人倾向于使用Darin Dimitrov在他的解决方案中展示的方法。 这使您能够使用数据注释方法进行验证,并在与当前任务相对应的每个ViewModel上具有单独的数据属性。 要最小化模型和视图模型之间的复制工作量,您应该查看AutoMapper或ValueInjecter。两者都有各自的优势,所以请检查两者。
另一种可能的方法是从IValidatableObject派生您的viewmodel或模型。这使您可以选择实现Validate函数。 在validate中,您可以返回ValidationResult元素列表,也可以为您在验证中检测到的每个问题发出一个yield return。
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;
}
答案 5 :(得分:14)
客户端 为了禁用表单验证,下面给出了基于我的研究的多个选项。希望其中一个能为你效劳。
选项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();
}
}
}
这里描述了一种更好的方法Enable/Disable mvc server side validation dynamically
答案 6 :(得分:7)
我认为这里最干净的方法是禁用客户端验证,在服务器端你需要:
似乎即使是自定义视图模型也不会解决问题,因为那些“预先回答”字段的数量可能会有所不同。如果他们不这样做自定义视图模型可能确实是最简单的方法,但使用上述技术可以解决您的验证问题。
答案 7 :(得分:5)
这是评论中其他人的答案......但它应该是一个真正的答案:
$("#SomeValue").removeAttr("data-val-required")
使用具有[Required]
属性
答案 8 :(得分:2)
当我为我的模型创建编辑视图时,我遇到了这个问题,我想只更新一个字段。
我对最简单方法的解决方案是使用以下两个字段:
<%: Html.HiddenFor(model => model.ID) %>
<%: Html.HiddenFor(model => model.Name)%>
<%: Html.HiddenFor(model => model.Content)%>
<%: Html.TextAreaFor(model => model.Comments)%>
评论是我仅在编辑视图中更新的字段,其中没有必需属性。
ASP.NET MVC 3实体
答案 9 :(得分:1)
AFAIK您无法在运行时删除属性,只能更改其值(即:readonly true / false)look here for something similar。 作为另一种在不干扰属性的情况下执行所需操作的方法,我将使用ViewModel进行特定操作,这样您就可以插入所有逻辑而不会破坏其他控制器所需的逻辑。 如果您尝试获取某种向导(多步骤表单),则可以序列化已编译的字段,并使用TempData将它们带到您的步骤中。 (有关序列化反序列化的帮助,您可以使用MVC futures)
答案 10 :(得分:1)
@Darin所说的也是我所推荐的。但是我会添加它(并且响应其中一条评论)你实际上也可以将这种方法用于基本类型,如bit,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
}
答案 11 :(得分:1)
从MVC 5开始,可以通过在global.asax
中添加它来轻松实现。
DataAnnotationsModelValidatorProvider.AddImplicitRequiredAttributeForValueTypes = false;
答案 12 :(得分:1)
我一直在寻找一种解决方案,可以在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'方法。在此替代中,我过滤了所需的模型验证器。 现在是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()
找出谁是
进行模型验证。答案 13 :(得分:0)
如果您不想使用其他ViewModel,则可以在视图上禁用客户端验证,还可以删除服务器上要忽略的属性的验证。请查看此答案以获得更深入的解释https://stackoverflow.com/a/15248790/1128216
答案 14 :(得分:0)
在我的情况下,出于重复使用的目的,在许多页面中使用了相同的模型。所以我所做的就是创建了一个自定义属性,用于检查排除项
def lda_fit(X,Y):
# class means
unique_classes=np.unique(Y)
mu=np.zeros((len(unique_classes),X.shape[1]))
for i,name in enumerate(unique_classes):
mu[i,:] = X[Y==name,:].mean(axis=0)
mupos=mu[1]
muneg=mu[0]
mupos=mupos.reshape(155,2)
muneg=muneg.reshape(155,2)
Xneu=X[0].reshape(155,2)
# D-by-D inter class covariance matrix (signal)
Sinter = np.dot((muneg-mupos),(muneg-mupos).T)
# D-by-D intra class covariance matrices (noise)
Sintra =np.dot((Xneu-mupos),(Xneu-mupos).T)+np.dot((Xneu-muneg),(Xneu-muneg).T)
# solve eigenproblem
eigvals, eigvecs = sp.linalg.eig(Sinter,Sintra)
w = eigvecs[:,eigvals.argmax()]
# bias term
b = (w.dot(mupos) + w.dot(muneg))/2.
# return the weight vector
return w,b
lda_fit(X,Y)
和您的控制器中
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
}
答案 15 :(得分:-1)
是的,可以禁用必需属性。从RequiredAtribute创建您自己的自定义类属性(示例代码名为ChangeableRequired),并添加一个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;
这感觉很干净吗?
注意:当您的对象实例处于活动状态时,将禁用上述验证\ active ...