Mar*_*ell 6 c# oop asp.net-mvc model-binding viewmodel
在我的ASP.NET MVC应用程序中,我有一个接口,它充当几个不同视图模型的模板:
public interface IMyViewModel
{
Client Client1 { get; set; }
Client Client2 { get; set; }
Validator Validate();
}
Run Code Online (Sandbox Code Playgroud)
所以,我的视图模型定义如下:
public interface MyViewModel1 : IMyViewModel
{
Client Client1 { get; set; }
Client Client2 { get; set; }
// Properties specific to MyViewModel1 here
public Validator Validate()
{
// Do ViewModel-specific validation here
}
}
public interface MyViewModel2 : IMyViewModel
{
Client Client1 { get; set; }
Client Client2 { get; set; }
// Properties specific to MyViewModel2 here
public Validator Validate()
{
// Do ViewModel-specific validation here
}
}
Run Code Online (Sandbox Code Playgroud)
然后我当前有一个单独的控制器操作来使用模型绑定对每个不同的类型进行验证:
[HttpPost]
public ActionResult MyViewModel1Validator(MyViewModel1 model)
{
var validator = model.Validate();
var output = from Error e in validator.Errors
select new { Field = e.FieldName, Message = e.Message };
return Json(output);
}
[HttpPost]
public ActionResult MyViewModel2Validator(MyViewModel2 model)
{
var validator = model.Validate();
var output = from Error e in validator.Errors
select new { Field = e.FieldName, Message = e.Message };
return Json(output);
}
Run Code Online (Sandbox Code Playgroud)
这很好 - 但如果我有30种不同的视图模型类型,那么就必须有30个单独的控制器动作,除了方法签名之外都有相同的代码,这似乎是不好的做法.
我的问题是,我如何整合这些验证操作,以便我可以传递任何类型的视图模型并调用它的Validate()方法,而不关心它是哪种类型?
起初我尝试使用接口本身作为动作参数:
public ActionResult MyViewModelValidator(IMyViewModel model)...
Run Code Online (Sandbox Code Playgroud)
但这不起作用:我得到一个Cannot create an instance of an interface例外.我以为模型的一个实例会传递给控制器动作,但显然事实并非如此.
我确定我错过了一些简单的事情.或许我刚才接近这一切都错了.谁能帮我吗?
mar*_*ind 11
您无法使用该接口的原因是序列化.当请求进入时,它只包含表示对象的字符串键/值对:
"Client1.Name" = "John"
"Client2.Name" = "Susan"
Run Code Online (Sandbox Code Playgroud)
当调用action方法时,MVC运行时会尝试创建值以填充方法的参数(通过称为模型绑定的过程).它使用参数的类型来推断如何创建它.正如您所注意到的,参数不能是接口或任何其他抽象类型,因为运行时无法创建它的实例.它需要一种具体的类型.
如果你想删除重复的代码,你可以编写一个帮助器:
[HttpPost]
public ActionResult MyViewModel1Validator(MyViewModel1 model)
{
return ValidateHelper(model);
}
[HttpPost]
public ActionResult MyViewModel2Validator(MyViewModel2 model)
{
return ValidateHelper(model);
}
private ActionResult ValidateHelper(IMyViewModel model) {
var validator = model.Validate();
var output = from Error e in validator.Errors
select new { Field = e.FieldName, Message = e.Message };
return Json(output);
}
Run Code Online (Sandbox Code Playgroud)
但是,对于每种模型类型,您仍然需要不同的操作方法.也许还有其他方法可以重构您的代码.似乎模型类的唯一区别是validataion行为.您可以在模型类中找到另一种编码验证类型的方法.
小智 5
您可以查看:http://msdn.microsoft.com/en-us/magazine/hh781022.aspx.
这是因为DefaultModelBinder无法知道IMyViewModel应该创建什么具体类型.对于解决方案,您可以创建自定义模型绑定器并指示如何创建和绑定接口实例.