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

时间:2013-04-23 23:24:30

标签: asp.net-mvc-4

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

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

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

  1. 我想知道如何使用@ Html.HiddenFor方法实现我在下面所做的工作。我无法弄清楚如何用反射中的属性信息编写lambda表达式。
  2. 有没有更好的方法来处理将Category对象传递给我的控制器。我的观点是强类型的。它是否应该知道在帖子上传回Product对象。
  3. 我的复杂类型如下。

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

    感谢。

2 个答案:

答案 0 :(得分:4)

为何隐藏?

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

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,则该代码将不起作用。

答案 1 :(得分:0)

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

结合使用