【问题标题】:How to POST complex models to action using reflection如何使用反射将复杂模型发布到操作
【发布时间】:2017-02-09 05:18:04
【问题描述】:

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

将我的 Product 对象的属性 CategoryType 传递回 HttpPost 上的控制器的最佳方法是什么。

我正在寻找一种方法,这样我就不必手动写出每个属性。 我目前正在使用反射来迭代 Category 类型的属性,并使用 @Html.Hidden 方法将它们添加为隐藏输入变量。 这行得通,但我想知道我的做法是否正确(最佳做法)。

  1. 我想知道如何使用@Html.HiddenFor 方法实现我在下面所做的事情。我不知道如何使用反射中的属性信息编写 lambda 表达式。
  2. 有没有更好的方法来处理将 Category 对象传递给我的控制器。我的观点是强类型的。它是否应该知道在帖子中传回 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);
    }
}

加上添加视图

    @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>

}

谢谢。

【问题讨论】:

    标签: asp.net-mvc-4


    【解决方案1】:

    为什么要隐藏?

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

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

    还有风景

    @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 类中有一百个字段,则可以放大这种方法的优势。并且您有一个用例,其中只有部分字段将被编辑。

    脚手架

    当然,您仍然可以按照自己的方式进行操作。但是,与其进行会产生开销的反射,不如摆脱它并做脚手架。以这种方式,您不必手动编码类的所有字段。这里有两个很好的链接可以帮助您开始使用脚手架:

    使用反射

    但如果你坚持使用反射,那是完全有可能的(你的代码中几乎已经有了)

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

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

    【讨论】:

    • 隐藏 CategoryId 的原因是他们已经在之前的 View 中选择了他们的 Category。例如,他们已经查看了所有“奶酪”,并添加了新的“奶酪”。
    • 这是可以理解的,我什至在我的例子中有一个隐藏字段。但是你的其他领域呢?您无需不必要地正确传递它们。
    • 隐藏 CategoryId 的原因是他们已经在之前的 View 中选择了他们的 Category。例如,他们已经查看了所有“奶酪”,并添加了新的“奶酪”。我一直在使用 nuget.org/packages/twitter.bootstrap.mvc4 包,这是所有反射和自动脚手架的来源。我会检查脚手架,看看它是如何工作的。我现在只处理 CategoryId 而不是 ViewModel 中的整个类别对象。
    • 你说得对,我不需要不必要地传递它们。这回答了我的问题的第 2 部分。
    • 第 1 部分的问题更像是一个学术问题,即是否可能。我可以在 lambda 表达式中对我的模型使用反射来访问属性吗?
    【解决方案2】:

    我相信 MVC4 有HiddenInputAttribute。您可以将其与 Html.EditorFor 结合使用。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-05-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-12-18
      相关资源
      最近更新 更多