我有20个字段的模型。模型的部分验证
我的观点分为4个面板,每个面板有5个区域;用户可以一次单独保存一个面板的数据。
我创建了4个视图,每个面板一个。这些视图都使用相同的模型,因为这些数据都在同一个数据库表中,所以我有一个单一的CRUD集。
我的问题是如何才能打开/关闭数据注解的必填字段只有当这些显示在其特定的面板?
如果我宣布他们都在20场模型的属性,它们将失效模式,即使他们不显示在屏幕上...
我有20个字段的模型。模型的部分验证
我的观点分为4个面板,每个面板有5个区域;用户可以一次单独保存一个面板的数据。
我创建了4个视图,每个面板一个。这些视图都使用相同的模型,因为这些数据都在同一个数据库表中,所以我有一个单一的CRUD集。
我的问题是如何才能打开/关闭数据注解的必填字段只有当这些显示在其特定的面板?
如果我宣布他们都在20场模型的属性,它们将失效模式,即使他们不显示在屏幕上...
您最好将数据注释移动到查看模型。您可以为每个视图创建不同的模型,以便只触发受该视图影响的注释。
这就是说,有时很难重新设计你的数据模型。在这种情况下,您可以使用自定义的requiredif注释来添加触发部分数据验证的属性。具体请参阅RequiredIf Conditional Validation Attribute。
我在第一个MVC项目中遇到了这个问题。以下是我如何解决这个问题。请注意,我将它们放在Model \ DataValidations.cs文件中以保持我生成的类清洁。
[MetadataType(typeof(Location_Validation))]
public partial class Location
{
public bool DisableValidation { get; set; }
}
public class Location_Validation : HomeIndex_Validation
{
[RequiredIf(DependentProperty = "DisableValidation", TargetValue = false, ErrorMessageResourceType = typeof(Language), ErrorMessageResourceName = "FieldRequired")]
[MinLength(2, ErrorMessageResourceType = typeof(Language), ErrorMessageResourceName = "FieldTooShort")]
[MaxLength(50, ErrorMessageResourceType = typeof(Language), ErrorMessageResourceName = "FieldTooLong")]
[Display(ResourceType = typeof(Language), Name = "City")]
public string City { get; set; }
[RequiredIf(DependentProperty = "DisableValidation", TargetValue = false, ErrorMessageResourceType = typeof(Language), ErrorMessageResourceName = "FieldRequired")]
[MinLength(2, ErrorMessageResourceType = typeof(Language), ErrorMessageResourceName = "FieldTooShort")]
[MaxLength(2, ErrorMessageResourceType = typeof(Language), ErrorMessageResourceName = "FieldTooLong")]
[ReadOnly]
[Display(ResourceType = typeof(Language), Name = "State")]
public string State { get; set; }
[RequiredIf(DependentProperty = "DisableValidation", TargetValue = false, ErrorMessageResourceType = typeof(Language), ErrorMessageResourceName = "FieldRequired")]
[MinLength(2, ErrorMessageResourceType = typeof(Language), ErrorMessageResourceName = "FieldTooShort")]
[MaxLength(50, ErrorMessageResourceType = typeof(Language), ErrorMessageResourceName = "FieldTooLong")]
[Display(ResourceType = typeof(Language), Name = "County")]
public string County { get; set; }
[Required(ErrorMessageResourceType = typeof(Language), ErrorMessageResourceName = "FieldRequired")]
[MaxLength(5, ErrorMessageResourceType = typeof(Language), ErrorMessageResourceName = "FieldInvalid")]
[MinLength(5, ErrorMessageResourceType = typeof(Language), ErrorMessageResourceName = "FieldInvalid")]
[RegularExpression(@"^\d+$", ErrorMessageResourceType = typeof(Language), ErrorMessageResourceName = "FieldInvalid")]
[Display(ResourceType = typeof(Language), Name = "ZipCode")]
public string ZipCode { get; set; }
}
不是最好的解决方案,但它的工作原理和数据模型完全验证,因为用户通过网站进展。当然,如果用户输入一个值,格式化验证将被强制执行。
真的有没有简单的方法来完成这项工作。我唯一的建议是一个自定义模型验证器,它考虑了每个局部视图中的前一个字段。例如:
class LabRatModel
{
public int a { get; set; }
public int b { get; set; } // Say the partial splits right here
public int c { get; set; }
public int d { get; set; }
}
在你自定义的验证,尝试:
public override bool IsValid(object model)
{
var labrat = model as LabRatModel;
return labrat.b > 0 && labrat.c > 0;
}
的一点是要检查前一个字段,并从那里走。
好建议,必填如果我正在寻找解决方案。谢谢! – MaurGi
由于B2K Answer指出,使用ViewModel有优势。我不是一直反复地来回映射字段的粉丝,所以我喜欢使用MetaData和Validation类来封装这个概念。
public TheMainClass
{
public string Prop1 { get; set; }
public string Prop2 { get; set; }
public string Prop3 { get; set; }
public string Prop4 { get; set; }
}
如果我只显示和验证每个支撑每个视图,然后我将创建4款专为验证设计:
[Metadata(typeof(Main1Model.IView1Validation))]
public Main1Model : TheMainClass
{
internal interface IView1Validation
{
[Required]
string Prop1 { get; set; }
[ScaffoldColumn(false)]
string Prop2 { get; set; }
//etc
}
}
ViewModel2:
[Metadata(typeof(IView2Validation))]
public Main2Model : TheMainClass
{
internal interface IView1Validation
{
[HiddenInput(DisplayValue = false)]
[Required]
string Prop1 { get; set; }
[Required]
string Prop2 { get; set; }
//etc
}
}
等等。随着观点的进展,如果有人决定使用浏览器工具来隐藏隐藏字段,您仍然有验证。
一个视图模型将封装所有视图模式:(我总是这样做,因为B2K建议为好)
public MainViewModel
{
public MainModel { get; set; }
}
等。
然后操作会看起来像:
[HttpPost]
public ActionResult View1(MainViewModelmodel)
{
if (ModelState.IsValid)
{
TempData["View1"] = model;
return this.RedirectToAction("View2");
}
return this.View(model);
}
public ActionResult View2()
{
model = TempData["View"] as Main1ViewModel;
if (model == null)
{
return this.RedirectToAction("View1");
}
return this.View(model)
}
[HttpPost]
public ActionResult View2(MainViewModel model)
{
// and so on (like HttpPost View1
}
然后你可能会问..但等待这是如何工作的? ViewModel使用基类型,这就是MVC的魔力。你会发现,View2.cshtml
是强类型来MainViewModel
但视图使用具体类型传入,而不是定义类型的传递
所有视图看起来像(甚至可以是相同的观点。):
@model MainViewModel
@EditFor(m => m.MainModel.Prop1)
@EditFor(m => m.MainModel.Prop2)
@EditFor(m => m.MainModel.Prop3)
@EditFor(m => m.MainModel.Prop4)
如果Model1View与支架fals
ê传递,()■不会产生任何HTML元素editfor。
随着用户的进展和您指定[HiddenInput]
的editfor()S创建一个隐藏字段。
真棒酱的最后一位是双重的;首先你不必坚持内存模型(因为每一个模型是完全传递给视图),其次后退按钮的工作原理,因为该模型被存储在视图投入(包括隐藏字段)
谢谢 - 我想和子类类似的方法,但是我觉得RequiredIf是一个简单的解决方案我案件。 – MaurGi
为了与“DRY”原则保持一致,当您的域实体可以整齐地包含所有需要的验证元数据注释时,我认为将所有实体映射到视图模型是有害的。在为这个部分验证问题寻找一个更令人满意的解决方案时,我在视图模型中保留一个“步骤”数,并将我的域实体添加为该视图中的子组件。我发现我可以在我的if(Model.IsValid){和删除违规条目之前检查此步数,从而保留域实体上的注释。例如。
public MainViewModel
{
public ModelType MainModel { get; set; }//Domain entity containing my validation metadata annotations
public int StepCount { get; set; }
}
然后我的行动
public ActionResult SubmitProcess(MainViewModel model)
{
int NextStep = model.StepCount+1;
if (NextStep <= 4)//I am not ready to perform the below validation at this time.
ModelState.Remove("MainModel.Prop1");//So remove the key!
if (!ModelState.IsValid)//Now validate and allow next step only if valid
NextStep = model.StepCount;//Failed so retract movement to NextStep.
if (NextStep != model.StepCount)
{
ModelState.Remove("StepCount");//Another 'gotcha' - model needs a 'nudge' to refresh hidden fields!
model.StepCount = NextStep;
}
return View(model)//model.StepCount now incremented only if partial validation passed - so do an action based on that.
}
有没有这样的事ASP.NET MVC 6(还)。请检查您认为正在使用的技术的版本号... – Charles
呵呵你是对的,它是MVC5(与实体框架verion 6.1混淆) - 将更新post -thx。 – MaurGi
可能有充分的理由需要这些字段,任何绕过验证的努力都可能导致比解决问题更多的问题。话虽如此,你有没有考虑使用默认值? – RyanCJI