繁体   English   中英

EditorFor 继承模型MVC

[英]EditorFor Inheritance Model MVC

我的 Post 调用没有返回正确的模型类型。 它总是使用 baseObject 而不是我从 Get 传入的正确派生对象

RestaurantViewModel.cs

public class RestaurantViewModel{
   public Food BaseFoodObject{get;set;}
}

食品.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}
}

面包模板的编辑器。 显示单位并允许用户编辑

索引.html

@Model RestaurantViewModel

@using(Html.BeginForm("SaveFood", "Food"))
{
  @Html.EditorFor(m=>m.BaseFoodObject)
 <input type="submit" value="Process"/>
}

面包.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 ObjectUnit属性不会与RestaurantViewModel一起传入。 原因是 RestaurantViewModel 使用Food对象而不是Bread

我希望可以修改 EditorFor 并告诉它使用视图中模型或我在显示时传入的对象类型。

谢谢

更新 1:我通过使用自定义绑定器并使用工厂来决定我真正想要哪个对象来解决这个问题。 这有助于构建我想要的正确模型

问题出在帖子上。 发布后,您所拥有的只是一组发布的数据和一个类型为RestaurantViewModel的参数。 模型绑定器在Food上设置所有适当的字段,因为它只知道这些。 其他一切都被丢弃。 对此没有什么可以做的。 如果您需要发布与Bread相关的字段,那么您的财产类型必须是Bread 这是唯一可行的方法。

MVC 是无状态的。 几个参考

您的问题中有几个陈述与此冲突,以及 MVC 绑定的工作原理,例如:

我的 Post 调用没有返回正确的模型类型。

可能只是术语,但您的 Post 调用不会“返回模型类型” - 它进入 post 操作中定义的模型,在本例中为RestaurantViewModel

而不是我从 Get 传入的正确派生对象

因为它是无状态的,它对你从get传入的模型一无所知......绝对没有。

通过 getaction+view.cshtml+model 呈现的最终 html 未链接到 postaction。 您可以轻松地获取渲染的 html,保存它,重新启动您的 PC,重新加载渲染的 html,它将以完全相同的方式工作。

一种修改 EditorFor 并告诉它使用视图中的模型或我在显示时传入的对象类型的方法

当您使用EditorFor它会根据绑定到的模型设置IDname属性,因此它已经这样做了,但也许您没有绑定到要绑定到的模型以获取正确的id


因此,对于这个问题,如果在“普通”C# 代码中您要实例化RestaurantViewModel的新实例,您希望BaseFoodObject 的类型是什么?

这就是 ModelBinder 正在做的 - 它正在创建一个新的RestaurantViewModel

由于您的 post action 方法的签名不包含与Bread任何内容 - 所有面包属性都将被忽略。

一些选项:


绑定后检查食物属性并手动读取它们(可能是最快+最简单但不是很“mvc-ish”)

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

相关链接,但不是此特定案例的解决方案)


另一种选择可能是将 Restaurant 类型更改为泛型,但需要进行更多更改(最好使用接口)和更多详细信息(此处作为想法而不是解决方案提供)

基本知识是:

public class RestaurantViewModel<T> 
     where T: Food
{
}

public ActionResult Post(RestaurantViewModel<Bread> viewModelPost)

public ActionResult Post(RestaurantViewModel<Milk> viewModelPost)

但我还没有确认默认的 ModelBinder 在这种情况下是否可以工作。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM