我一直在使用ASP.NET MVC2进行一些实验,并遇到了一个有趣的问题。
我想在MVC应用程序中定义将用作模型的对象周围的接口。另外,我想通过使用验证属性标记此接口的成员来在功能上利用新的DataAnnotation。
因此,如果我的网站有“Photo”对象,我将定义以下界面:
public interface IPhoto
{
[Required]
string Name { get; set; }
[Required]
string Path { get; set; }
}
我将定义以下实现:
public class PhotoImpl : IPhoto
{
public string Name { get; set; }
public string Path { get; set; }
}
我的MVC App控制器可能包含以下方法:
public class PhotoController : Controller
{
[HttpGet]
public ActionResult CreatePhoto()
{
return View();
}
[HttpPost]
public ActionResult CreatePhoto(IPhoto photo)
{
if(ModelState.IsValid)
{
return View();
}
else
{
return View(photo);
}
}
}
最后,为了将PhotoImpls绑定到这些操作方法中的参数,我可能会对DefaultModelBinder实现以下扩展:
public class PhotoModelBinder : DefaultModelBinder
{
public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
{
if(bindingContext.ModelType == typeof(IPhoto))
{
IPhoto photo = new PhotoImpl();
// snip: set properties of photo to bound values
return photo;
}
return base.BindModel(controllerContext, bindingContext);
}
}
除了我的控制器中的ModelState.IsValid属性似乎没有注意到IPhoto实现的[Required]属性中的无效值(例如,null)之外,所有内容似乎都运行良好。
我怀疑我忽略了在我的ModelBinder实现中设置一些重要的状态。任何提示?
答案 0 :(得分:9)
我有同样的问题。答案是在自定义模型绑定器中覆盖BindModel(),而不是覆盖CreateModel()......
protected override object CreateModel(ControllerContext controllerContext, ModelBindingContext bindingContext, System.Type modelType)
{
if (modelType == typeof(IPhoto))
{
IPhoto photo = new PhotoImpl();
// snip: set properties of photo to bound values
return photo;
}
return base.CreateModel(controllerContext, bindingContext, modelType);
}
然后你可以让基础BindModel类通过验证来完成它的工作: - )
答案 1 :(得分:7)
在检查System.Web.MVC.DefaultModelBinder的源代码之后,看起来这可以使用稍微不同的方法来解决。如果我们更依赖于BindModel的基本实现,看起来我们可以构建一个PhotoImpl对象,同时仍然从IPhoto中提取验证属性。
类似的东西:
public class PhotoModelBinder : DefaultModelBinder
{
public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
{
if (bindingContext.ModelType == typeof(IPhoto))
{
ModelBindingContext newBindingContext = new ModelBindingContext()
{
ModelMetadata = ModelMetadataProviders.Current.GetMetadataForType(
() => new PhotoImpl(), // construct a PhotoImpl object,
typeof(IPhoto) // using the IPhoto metadata
),
ModelState = bindingContext.ModelState,
ValueProvider = bindingContext.ValueProvider
};
// call the default model binder this new binding context
return base.BindModel(controllerContext, newBindingContext);
}
else
{
return base.BindModel(controllerContext, bindingContext);
}
}
}
答案 2 :(得分:0)
您是否尝试在模型上放置[必需]属性并重新测试?将属性应用于接口可能有困难。