Pie*_* SS 14 c# model-view-controller asp.net-mvc model-validation validationattribute
我知道在MVC中有很多方法可以进行模型验证,并且有很多关于这个主题的文档.不过,我不太清楚什么是用于验证的性能,最好的方法模型这是"子模型"的同一类型.
请记住以下内容
TryUpdateModel/TryValidateModel方法MainModel该类有一个强类型视图,用于呈现整个显示视图这可能听起来有点令人困惑但我会抛出一些代码来澄清.以下面的类为例:
MainModel:
class MainModel{
public SomeSubModel Prop1 { get; set; }
public SomeSubModel Prop2 { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
SomeSubModel:
class SomeSubModel{
public string Name { get; set; }
public string Foo { get; set; }
public int Number { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
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
}
Run Code Online (Sandbox Code Playgroud)
我相信这段代码直到现在才有意义(如果不是这样的话,请纠正我)因为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; }
}
Run Code Online (Sandbox Code Playgroud)
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) { }
}
Run Code Online (Sandbox Code Playgroud)
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) { }
}
Run Code Online (Sandbox Code Playgroud)
行动
[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);
}
Run Code Online (Sandbox Code Playgroud)
我们在一个应用程序中也有类似的SomeSubModel情况,其中每个应用程序都代表一项作业的参数设置。由于每种类型的作业都有不同数量和类型的参数,因此我们的作业模型具有这些参数的集合,而不仅仅是设置属性。
我们有一个子类JobParameter为不同的可用类型(StringParameter, BoolParameter, DoubleParameter, ...)。这些子类有自己的验证属性集。
共享的“JobParameterModel”用于将参数传递到视图。
对于验证,返回的模型将转换为其特定的作业参数。
参数类型:
public enum ParameterType
{
Empty = 0,
Boolean = 1,
Integer = 2,
String = 3,
DateTime = 4,
...
}
Run Code Online (Sandbox Code Playgroud)
作业参数:
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]();
}
}
Run Code Online (Sandbox Code Playgroud)
布尔参数:
[ABoolClassLevelValidationAttribute]
class BoolParameter:JobParameter
{
[AValidationAttribute]
public override string Foo {get;set;}
}
....
Run Code Online (Sandbox Code Playgroud)
在我们的验证框架(据我所知,它的建模与 MS 的非常接近)中,ViewModel 总是转换回其域对象以进行验证。
参数型号:
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);
}
}
Run Code Online (Sandbox Code Playgroud)
控制器:
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);
}
}
Run Code Online (Sandbox Code Playgroud)
考虑到您的具体情况,您不需要变得如此复杂(或者相信我们的验证框架的具体细节将适合您)。
为每个道具编辑/保存操作:
为每个道具创建验证模型。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);
}
Run Code Online (Sandbox Code Playgroud)
这样,您就可以对 Prop1 和 Prop2 使用相同的强类型视图。
| 归档时间: |
|
| 查看次数: |
9305 次 |
| 最近记录: |