【问题标题】:Binding any field prefix to an action parameter in C# MVC 4/5在 C# MVC 4/5 中将任何字段前缀绑定到操作参数
【发布时间】:2014-07-16 09:48:30
【问题描述】:

我正在使用 C# ASP.Net MVC 4 和 MVC 5。

我使用了一个聚合模型VmVehicleGroup,它看起来有点像:

public class VmVehicleGroup {
    public VehicleTypeEnum Type { get; set; }
    public List<VmVehicle> Vehicles { get; set; }
    public VmVehicle Editable { get; set;}
}

主视图对每个组都有部分视图,例如,

@Html.Partial(x => x.Cars, "_VehicleEditor")

@Html.Partial(x => x.Bus, "_VehicleEditor")

@Html.Partial(x => x.Truck, "_VehicleEditor")

每组部分显示Model.Vehicles,并为Model.Editable提供一个编辑器模板

我的问题来自 ModelState。每个部分将为 Model.Editable 呈现相同的输入字段名称/ID。当存在 ModelState 验证错误时,“Car”部分的验证错误将出现在所有其他表单上,而不仅仅是 Car。我通过在编辑器中为模型添加前缀来解决这个问题,例如:

ViewData.TemplateInfo.HtmlFieldPrefix = Model.Type.ToString(); // VehicleTypeEnum

添加/编辑表单现在将提交带有字段发布数据前缀的Model.Editable,即:Car.Reg、Car.Name、Car.Type 和 Car.Id。我的问题出现在 MVC 操作上。我目前的操作如下所示:

[ValidateAntiForgeryToken]
[AcceptVerbs(HttpVerbs.Post)]
[Route("Edit", Name = "EditVehicle")]
public ActionResult Edit([Bind(Prefix = "Car")] VmVehicle car, [Bind(Prefix = "Bus")] VmVehicle bus, [Bind(Prefix = "Truck")] VmVehicle truck, ....)
{
    var model = car ?? bus ?? truck;

    ...
}

我的问题是,这是维护的噩梦 - 对于每个 VehicleTypeEnum,我需要添加额外的绑定参数。我不能对带前缀的模型执行单一操作。

我尝试过使用public ActionResult Edit(VmVehicle model) {},但前缀阻碍了 MVC 绑定。不幸的是,MVC 似乎也不允许您绑定通配符或逗号分隔的前缀,即:*.Car 或 Car,Bus,Truck。

是否可以鼓励 MVC 操作接受任何前缀,同时保留 ModelState 验证错误的前缀?

【问题讨论】:

    标签: c# asp.net-mvc model-view-controller


    【解决方案1】:

    我看到,在您看来,您对不同类型的车辆有不同的部分。这意味着您事先知道有哪些不同的车辆类型。

    正如您之前所知道的,您只需在创建视图模型时进行组的分离。 IE。为汽车、卡车、公共汽车创建一个包含不同列表的视图模型...这样您就可以在客户端获得所需的前缀。

    那么发布操作呢?好吧,与其接收列表作为单独的参数,不如接收一个类似于您用来呈现编辑器的类,即

    使用具有此属性的类来创建编辑器(将其用作您的视图模型):

    public class VehiclesViewModel
    {
      public List<Vehicle> Cars { get; set;}
      public List<Vehicle> Buses { get; set;}
      // other stuff here!
    }
    

    如果你使用这样的类,它也有汽车、公共汽车等列表,数据将自动绑定,即使用的插入:

    public ActionResult Edit([Bind(Prefix = "Car")] VmVehicle car, 
         [Bind(Prefix = "Bus")] VmVehicle bus, ...)
    

    使用这样的操作:

    public ActionResult Edit(VehiclesViewModel vehicles)
    

    模型绑定器将为您处理前缀,并将每辆车绑定到其相应的列表。

    显示和编辑模板

    但是,如果您为每种类型的车辆使用不同的类,您可以使用自定义的显示和编辑模板,这可以让您的生活更轻松。 IE。您可以定义适用于给定数据类型的显示和编辑模板。因此,如果您对每种类型的车辆都有不同的类,您可以为每个不同的类使用显示和编辑模板,并使用“DisplayFor”或EditorFor,您将自动获得所需的视图。此链接中的一些示例:

    (我不明白你到底在做什么,所以我可以给出更具体的解释)

    模型绑定复杂对象列表

    人们发现 MVC 的另一个经典问题是,当他们想要绑定必须编辑的复杂对象列表时,他们不知道如何去做,以便将对象列表返回到服务器中在发布操作中。

    这个explanation by Phil Haack 是你能找到的最好的之一。

    【讨论】:

    • 嗨 - 我尝试过类似的方法。我想我想要避免的是传入一个由每个聚合组成的“主模型”,然后有一个非常大的 if 语句来选择正确的,即:if (model.Cars.Items.Any()) { /* using this */ } else if (model.Buses.Items.Any()) { /* etc */ },因为这会成为一个类似的负担 - 添加新类型意味着添加新测试。
    • 很难理解你到底在做什么。为什么不同类型的车辆形式不同,而代表的是同一类?为什么需要将相同的课程发布到不同的模型?太奇怪了。我认为它们应该是分离的类,并利用多态性。如果没有确切地看到你在做什么,使用同一个类来显示数据、编辑数据以及以不同的方式发布数据是没有意义的。
    • 当您在页面上多次使用相同的表单模型时,它将具有相同的 ModelState 标识符。 ModelState 错误将在所有表单上可见。我正在尝试通过 ModelState 验证来使用/实现多态端点。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-03-13
    • 1970-01-01
    相关资源
    最近更新 更多