如何使用反射将复杂模型POST到操作



我正在努力更好地理解和了解MCV4。

在HttpPost上传递Product对象的CategoryType属性给控制器的最好方法是什么

我正在寻找一种方法,所以我不必手写出每个属性。我目前使用反射来迭代类别类型的属性,并使用@Html将它们添加为隐藏的输入变量。隐藏的方法。这是有效的,但我想知道我是否在做正确的方式(最佳实践)。

  1. 我想知道如何实现我所做的使用@Html下面。HiddenFor方法。我不知道如何写lambda表达式与属性信息从反射。
  2. 有一个更好的方法来处理传递类别对象到我的控制器。我的视图是强类型的。它是否知道在post上传递Product对象?

我有一个复杂类型如下。

    public class Product
{
    [Key]
    public int Id { get; set; }
    [Required]
    public string ProductName { get; set; }
    public Category CategoryType { get; set; }
}

public class Category
{
    [Key]
    public int Id { get; set; }
    [Required]
    public string CategoryName { get; set; }
}

具有如下所示的控制器

 public class ProductController : Controller
{
    //
    // GET: /Product/
    public ActionResult Index()
    {
        return View();
    }
    public ActionResult Add()
    {
        //Add a new product to the cheese category.
        var product = new Product();
        var category = new Category { Id = 1, CategoryName = "Cheese" };
        product.CategoryType = category;
        return View(product);
    }
    [HttpPost]
    public ActionResult Add(Product product)
    {
        if (ModelState.IsValid)
        {
            //Add to repository code goes here
            //Redirect to Index Page
            return RedirectToAction("Index");
        }
        return View(product);
    }
}

的Add视图
    @model BootstrapPrototype.Models.Product
@{
    ViewBag.Title = "Add";
}
<h2>Add</h2>

@using (Html.BeginForm())
{
    @Html.DisplayFor(m => m.ProductName);
    @Html.EditorFor(m => m.ProductName);
    foreach(var property in Model.CategoryType.GetType().GetProperties())
    {
        //I know how to use the Hidden but would also know how to use the HiddenFor with reflections.
        @Html.Hidden("CategoryType." + property.Name, property.GetValue(Model.CategoryType));
    }
    <button type="submit">Add</button>
}

谢谢。

为什么隐藏?

我认为您将类别字段放在隐藏字段中的原因是因为您不希望用户更新它们,但您也需要这些值作为Product对象的一部分,否则您的产品对象将在没有类别(具有null值)的情况下保存。这正是ViewModel非常重要的原因。您创建一个视图模型,它接受您只需要的那些值的输入。因此,如果您需要创建一个只需要名称的产品,并且具有预先选择的不可编辑类别,那么您可以使用viewmodel:

public class ProductModel {
    public int Id {get;set;}
    public strnig Name{get;set;}
    public int CategoryId {get;set;}
}

和view

@model ProductModel 
@Html.HiddenFor(m=>m.Id)
@Html.HiddenFor(m=>m.CategoryId)
@Html.TextboxFor(m=>m.Name)
你可以从控制器方法

中获得的

public ActionResult Add() {
    var product = new ProductModel {
        CategoryId = getIdFromDb("cheese");
    };
    return View();
}
可以在控制器方法中接收的

[HttpPost]
public ActionResult Add(ProductMOdel input) {
    // map input to an entity
    var productENtity = mapModelToEntity(input);
    // save entity to your repo
}

如果在ProductCategory类中有100个字段,则可以放大此方法的优势。并且您有一个用例,其中只有一部分字段将被编辑。

<

脚手架/h2>

当然你仍然可以按你的方式去做。但是不要做反射,因为反射会增加开销你应该去掉它,用脚手架代替。通过这种方式,您不必手工编写类的所有字段。这里有两个很好的链接,可以让你开始使用脚手架:

  • EF代码优先和数据脚手架与ASP。Net MVC 3
  • mvc脚手架:一对多关系
使用反射

但是如果你坚持使用反射,那么这是完全可能的(你几乎在你的代码中有它)

@foreach(var property in Model.CategoryType.GetType().GetProperties())
{
    @Html.Hidden("Product." + property.Name, 
        property.GetValue(Model.CategoryType));
}

该代码的关键是"Product.",它允许模型绑定器完成它的工作-隐藏字段中的值将传递回您的POST控制器方法。但是,如果CategoryType为空,该代码将不起作用。

我相信MVC4有HiddenInputAttribute。可以与Html.EditorFor.

结合使用。

最新更新