我知道在MVC中有很多方法可以进行模型验证,并且有很多关于这个主题的文档。但是,我不太确定验证模型属性的最佳方法是什么,模型属于相同类型的“Sub Model”。
请记住以下
TryUpdateModel/TryValidateModel
种方法MainModel
类有一个强类型视图,用于呈现整体显示视图这可能听起来有点令人困惑,但我会抛出一些代码来澄清。以下面的类为例:
MainModel:
class MainModel{
public SomeSubModel Prop1 { get; set; }
public SomeSubModel Prop2 { get; set; }
}
SomeSubModel:
class SomeSubModel{
public string Name { get; set; }
public string Foo { get; set; }
public int Number { get; set; }
}
MainModelController:
class MainModelController{
public ActionResult MainDisplay(){
var main = db.retrieveMainModel();
return View(main);
}
[HttpGet]
public ActionResult EditProp1(){
//hypothetical retrieve method to get MainModel from somewhere
var main = db.retrieveMainModel();
//return "submodel" to the strictly typed edit view for Prop1
return View(main.Prop1);
}
[HttpPost]
public ActionResult EditProp1(SomeSubModel model){
if(TryValidateModel(model)){
//hypothetical retrieve method to get MainModel from somewhere
var main = db.retrieveMainModel();
main.Prop1 = model;
db.Save();
//when succesfully saved return to main display page
return RedirectToAction("MainDisplay");
}
return View(main.Prop1);
}
//[...] similar thing for Prop2
//Prop1 and Prop2 could perhaps share same view as its strongly
//typed to the same class
}
我相信这段代码直到现在才有意义(如果不是这样,请纠正我),因为TryValidateModel()
正在验证没有ValidationAttribute
的模型。
问题出在这里,哪里是最好的地方,或者是Prop1
和Prop2
的不同验证约束的最佳和最优雅方式仍然利用TryValidateModel()
并且不使用条件语句和ModelState.AddModelError()
通常,您可以在SomeSubModel
类中使用验证属性,但在这种情况下它不起作用,因为每个属性都有不同的约束。
其他选项是MainModel
类中可能存在自定义验证属性,但在这种情况下它也不起作用,因为SomeSubModel
对象直接传递给视图并且在验证时有没有引用它的MainModel
对象。
我能想到的唯一左侧选项是每个属性的ValidationModel,但我不是最好的方法。
这是我实施的解决方案,基于@MrMindor的回答。
Base ValidationModel类:
public class ValidationModel<T> where T : new()
{
protected ValidationModel() {
this.Model = new T();
}
protected ValidationModel(T obj) {
this.Model = obj;
}
public T Model { get; set; }
}
Prop1的验证模型
public class Prop1ValidationModel:ValidationModel<SomeSubModel>
{
[StringLength(15)]
public string Name { get{ return base.Model.Name; } set { base.Model.Name = value; } }
public Prop1ValidationModel(SomeSubModel ssm)
: base(ssm) { }
}
Prop2的验证模型
public class Prop2ValidationModel:ValidationModel<SomeSubModel>
{
[StringLength(70)]
public string Name { get{ return base.Model.Name; } set { base.Model.Name = value; } }
public Prop2ValidationModel(SomeSubModel ssm)
: base(ssm) { }
}
动作
[HttpPost]
public ActionResult EditProp1(SomeSubModel model){
Prop1ValidationModel vModel = new Prop1ValidationModel(model);
if(TryValidateModel(vModel)){
//[...] persist data
//when succesfully saved return to main display page
return RedirectToAction("MainDisplay");
}
return View(model);
}
答案 0 :(得分:4)
我们的某个应用程序中存在类似的情况,其中每个SomeSubModel
代表作业的参数设置。由于每种类型的作业都有不同数量和类型的参数,我们的作业模型包含这些参数的集合,而不仅仅是设置属性。
我们将JobParameter
子类化为可用的不同类型(StringParameter
,BoolParameter
,DoubleParameter
,...)。这些子类具有各自的验证属性集
共享的“JobParameterModel”用于将参数传递给视图
对于验证,返回的模型将转换为其特定的JobParameter
的 ParameterTypes:强>
public enum ParameterType
{
Empty = 0,
Boolean = 1,
Integer = 2,
String = 3,
DateTime = 4,
...
}
<强> JobParameter:强>
class JobParameter
{
[AValidationAttributeForAllParamters]
public string Name { get; set; }
public virtual string Foo { get; set; }
public int Number { get; set; }
public ParameterType Type {get;set;}
private static readonly IDictionary<ParameterType, Func<object>> ParameterTypeDictionary =
new Dictionary<ParameterType, Func<object>>{
{ParameterType.Empty, () => new EmptyParameter() },
{ParameterType.String, ()=>new StringParameter()},
{ParameterType.Password, ()=>new PasswordParameter()},
...
};
public static ScriptParameter Factory(ParameterType type)
{
return (ScriptParameter)ParameterTypeDictionary[type]();
}
}
<强> BoolParameter:强>
[ABoolClassLevelValidationAttribute]
class BoolParameter:JobParameter
{
[AValidationAttribute]
public override string Foo {get;set;}
}
....
在我们的验证框架(我被告知与MS的模型非常接近)中,ViewModel总是被转换回其域对象以进行验证。
ParameterModel:
class ParameterModel: JobParameter
{
public JobParameter ToDomain()
{
var domainObject = JobParameter.Factory(Type);
Mapper.Map(this, domainObject);
return domainObject;
}
public bool Validate()
{
var dom = ToDomain();
return TryValidate(dom);
}
}
<强>控制器:强>
class Controller(){
[HttpPost]
public ActionResult SaveParameter(JobParameter model){
if(TryValidateModel(model)){
//persist stuff to db.
//when succesfully saved return to main display page
return RedirectToAction("MainDisplay");
}
return View(main.Prop1);
}
}
为了您的具体情况,您不需要这么复杂(或者相信我们的验证框架的细节对您有用)。
为每个支柱编辑/保存操作:
为每个道具创建验证模型。 Prop1ValidationModel
,Prop2ValidationModel
[HttpGet]
public ActionResult EditProp1()
{
var main = db.retrieveMainModel();
db.Prop1.SubmitUrl = Url.Action("SaveProp1","Controller");
return View(main.Prop1);
}
[HttpPost]
public ActionResult SaveProp1(SomeSubModel model){
var validationModel = new Prop1ValidationModel{
///copy properties
};
if(TryValidateModel(validationModel)){
var main = db.retrieveMainModel();
main.Prop1 = model;
db.Save();
//when succesfully saved return to main display page
return RedirectToAction("MainDisplay");
}
return View(main.Prop1);
}
使用此功能,您可以对Prop1和Prop2使用相同的强类型视图。
答案 1 :(得分:2)
如果SomeSubModel具有不同的验证属性,具体取决于它是否在Prop1或Prop2中应用...意味着实际上prop1 end prop2的两个SomeSubModel是两个不同的类,因为如果它们具有相同的字段,则该字段的含义取决于它们是否附加到prop1或prop2(这就是为什么它们具有不同的验证属性。因此最好的方法是定义SomeSubClass的两个子类,比如SomeSubClass1和SomeSubClass2继承自Common SomeSubClass。一旦继承,你不能添加新的属性,但只是通过使用流畅的验证或使用MetaDataTypeAttribute从类定义中指定验证属性的新验证规则。所以你将有类似的东西:
[MetaDataType(typeof(ValidationClass1)]
public class SomeSubClass1: SomeSubclass{}
和
[MetaDataType(typeof(ValidationClass2)]
public class SomeSubClass2: SomeSubclass{}