我的帖子呼叫未返回正确的模型类型.它始终使用baseObject而不是我从Get中传入的正确派生对象.
RestaurantViewModel.cs
public class RestaurantViewModel{
public Food BaseFoodObject{get;set;}
}
Food.cs
public class Food{
public string Price{get;set;)
}
Bread.cs-从食物继承
public class Bread:Food{
public int Unit{get;set;}
}
Milk.cs-从食物继承
public class Milk:Food{
public string Brand{get;set}
}
面包模板的编辑器.显示单位并允许用户进行编辑
Index.html
@Model RestaurantViewModel
@using(Html.BeginForm("SaveFood", "Food"))
{
@Html.EditorFor(m=>m.BaseFoodObject)
<input type="submit" value="Process"/>
}
Bread.cshtml
@Model Bread
<div>
@Html.TextboxFor(bread=>bread.Unit)
</div>
FoodController.cs
public ActionResult Index(){
Bread bread = new Bread(){
Price = "$10",
Unit = 1
}
RestaurantViewModel viewModel = new RestaurantViewModel(){
BaseFoodObject = bread
}
return View(viewModel);
}
public ActionResult Post(RestaurantViewModel viewModelPost)
{
// When I inspect the viewModelPost, there is no attribute for unit
}
最后结果:
1.显示正确. EditorFor非常聪明,可以选择正确的编辑器模板并正确显示值
2.保存不起作用. Bread对象的Unit属性不会与RestaurantViewModel一起传递.原因是RestaurantViewModel使用Food对象而不是Bread
我希望可以修改EditorFor并告诉它使用视图中的模型或显示它时传入的对象类型.
谢谢
更新1:我通过使用自定义绑定程序并使用工厂来决定我真正想要的对象,解决了这个问题.这有助于构建我想要的正确模型
解决方法:
MVC是无状态的. references的couple.
您的问题中有一些与此矛盾的内容,以及MVC绑定的工作原理,例如:
My Post call does not return the correct Model type.
可能只是术语,但您的Post调用不会“返回模型类型”-它进入在post操作中定义的模型中,在本例中为RestaurantViewModel.
instead of the correct derived object that I passed in from the Get
因为它是无状态的,所以它对您从get传入的模型一无所知…绝对一无所获.
通过getaction view.cshtml模型呈现的最终html未链接到后期操作.您可以轻松地获取渲染的html,保存它,重新启动PC,重新加载渲染的html,它的工作方式完全相同.
a way to modify the EditorFor and tell it to use the Model in the View or the Object Type that I passed in when I display it
当您使用EditorFor时,它根据绑定到的模型设置ID和名称属性,因此它已经做到了,但是也许您未绑定到要绑定以获取正确ID的模型.
因此,问题在于,如果您要在“正常” C#代码中实例化RestaurantViewModel的新实例,那么您期望BaseFoodObject的类型是什么?
这就是ModelBinder所做的-创建一个新的RestaurantViewModel.
由于您的后操作方法签名不包括与Bread有关的所有内容-所有面包属性都将被忽略.
一些选项:
结合后检查食物特性并手动阅读(可能是最快,最简单的方法,但不是很“笨拙”)
public ActionResult Post(RestaurantViewModel viewModelPost)
{
if (!string.IsNullOrEmpty(Request.Form["Unit"]))
// it's a bread form
为了简化操作,您可以使用以下类型提供隐藏字段
if (Request.Form["Type"] == typeof(Bread).Name)
{
var bread = new Bread { Unit = Request.Form["Unit"] }
将面包添加到动作中以使其绑定
public ActionResult Post(RestaurantViewModel viewModelPost, Bread bread)
但是,显然,它不适用于牛奶.
因此可以使用ActionNameSelector扩展它以选择正确的动作
public ActionResult PostBread(RestaurantViewModel viewModelPost, Bread bread)
public ActionResult PostMilk(RestaurantViewModel viewModelPost, Milk milk)
[AttributeUsage(AttributeTargets.Method, AllowMultiple = false)]
public sealed class FoodSelectorAttribute : ActionNameSelectorAttribute
{
public override bool IsValidName(ControllerContext controllerContext, string actionName, MethodInfo methodInfo)
{
... check if provided parameters contains bread/milk
(related link,但不是此特定情况的解决方案)
另一个选择可能是将餐厅类型更改为通用类型,但需要进行一些其他更改(理想情况下使用接口)和更多详细信息(此处仅作为参考,而不是解决方案)
基础是:
public class RestaurantViewModel<T>
where T: Food
{
}
public ActionResult Post(RestaurantViewModel<Bread> viewModelPost)
public ActionResult Post(RestaurantViewModel<Milk> viewModelPost)
但我还不确定默认的ModelBinder在这种情况下是否可以使用.