MVC View ViewModel HttpPost返回值始终为NULL

Rob*_*urd 6 asp.net-mvc razor asp.net-mvc-4 asp.net-mvc-viewmodel

我通过表单HttpPost将ViewModel从我的View传递回Controller.但是,返回的值始终为NULL.

视图模型

public class vmCompanyAddress
{
    public StatelyTechAdmin.Models.Company Company { get; set; }
    public StatelyTechAdmin.Models.CompanyAddress Address { get; set; }

    public SelectList Counties { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

公司类模型

public class Company
{
    [Key]
    public virtual long CompanyId { get; set; }

    [Required]
    [Display(Name = "Company Name")]
    public virtual string Name { get; set; }

    public virtual DateTime CreatedDate { get; set; }

    public virtual IEnumerable<CompanyAddress> CompanyAddresses { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

CompanyAddress类模型

public class CompanyAddress
{
    [Key]
    public virtual long CompanyAddressId { get; set; }

    [Required]
    public virtual long CompanyId { get; set; }

    [ForeignKey("CompanyId")]
    public virtual Company Company { get; set; }

    [Required]
    public virtual int CopmanyAddressTypeId { get; set; }

    [ForeignKey("CopmanyAddressTypeId")]
    public virtual CompanyAddressType CompanyAddressType { get; set; }

    [Display(Name = "Address 1")]
    public virtual string Address1 { get; set; }

    [Display(Name = "Address 2")]
    public virtual string Address2 {get; set; }

    [Display(Name = "Town")]
    public virtual string Town { get; set; }

    [Display(Name = "City")]
    public virtual string City { get; set; }

    [Required]
    public virtual long CountyId { get; set; }

    [ForeignKey("CountyId")]
    [Display(Name = "County")]
    public virtual County County { get; set; }

    [Required]
    [Display(Name = "Postal Code")]
    public virtual string PostalCode { get; set; }

    public virtual DateTime CreatedDate { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

控制器(获取):

// GET: /Company/Create
    public ActionResult Create()
    {
        vmCompanyAddress vm = new vmCompanyAddress();
        vm.Counties = new SelectList(db.County, "CountyId", "Name", -1);
        //vm.Address = new CompanyAddress();
        //vm.Company = new Company();

        return View(vm);
    }
Run Code Online (Sandbox Code Playgroud)

控制员(职位):

[HttpPost]
    [ValidateAntiForgeryToken]
    public ActionResult Create(vmCompanyAddress company)
    {
        if (ModelState.IsValid)
        {
            db.Companies.Add(company.Company);

            //Amend Address Company & Address Type before save to DB
            company.Address.CompanyId = company.Company.CompanyId;
            company.Address.CopmanyAddressTypeId = 1;

            db.CompanyAddress.Add(company.Address);

            db.SaveChanges();
            return RedirectToAction("Index");
        }

        return View(company);
    }
Run Code Online (Sandbox Code Playgroud)

查看(创建)

    @model StatelyTechAdmin.ViewModels.vmCompanyAddress

@{
    ViewBag.Title = "Create";
}

<h2>Create</h2>

@using (Html.BeginForm()) {
    @Html.AntiForgeryToken()
    @Html.ValidationSummary(true)

    <fieldset>
        <legend>Company</legend>

        <div class="editor-label">
            @Html.LabelFor(model => model.Company.Name)
        </div>
        <div class="editor-field">
            @Html.EditorFor(model => model.Company.Name)
            @Html.ValidationMessageFor(model => model.Company.Name)
        </div>

        <div class="editor-label">
            @Html.LabelFor(model => model.Company.CreatedDate)
        </div>
        <div class="editor-field">
            @Html.EditorFor(model => model.Company.CreatedDate)
            @Html.ValidationMessageFor(model => model.Company.CreatedDate)
        </div>


        @* Invoice Address *@
        <div class="editor-label">
            @Html.LabelFor(model => model.Address.Address1)
        </div>
        <div class="editor-field">
            @Html.EditorFor(model => model.Address.Address1)
            @Html.ValidationMessageFor(model => model.Address.Address1)
        </div>

        <div class="editor-label">
            @Html.LabelFor(model => model.Address.Address2)
        </div>
        <div class="editor-field">
            @Html.EditorFor(model => model.Address.Address2)
            @Html.ValidationMessageFor(model => model.Address.Address2)
        </div>

        <div class="editor-label">
            @Html.LabelFor(model => model.Address.Town)
        </div>
        <div class="editor-field">
            @Html.EditorFor(model => model.Address.Town)
            @Html.ValidationMessageFor(model => model.Address.Town)
        </div>

        <div class="editor-label">
            @Html.LabelFor(model => model.Address.City)
        </div>
        <div class="editor-field">
            @Html.EditorFor(model => model.Address.City)
            @Html.ValidationMessageFor(model => model.Address.City)
        </div>

        @*<div class="editor-label">
            @Html.LabelFor(model => model.Address.County)
        </div>
        <div class="editor-field">
            @Html.DropDownListFor(model => model.Address.CountyId, Model.Counties)
        </div>*@

        <div class="editor-label">
            @Html.LabelFor(model => model.Address.PostalCode)
        </div>
        <div class="editor-field">
            @Html.EditorFor(model => model.Address.PostalCode)
            @Html.ValidationMessageFor(model => model.Address.PostalCode)
        </div>

        <p>
            <input type="submit" value="Create" />
        </p>
    </fieldset>
}
Run Code Online (Sandbox Code Playgroud)

任何人都可以提供任何建议,为什么我的返回ViewModel值在填充所有字段时为NULL?

我使用网络记录功能检查了谷歌浏览器浏览器,所有值都以JSON格式发回.

非常感谢.

------------编辑---------------

以下是我可以从Google Chrome网络监视器中看到的部分内容

公司名称:ABC123 Company.CreatedDate:2014/05/13 00:00:00 ....

所以肯定会被退回.

Mat*_*ion 11

我能够重现你的问题而感到困惑,因为我知道默认的MVC Model Binder理解复杂的类型.我剥离了大部分代码,只是试图用公司对象来做,但仍然失败了.然后我注意到在vmCompanyAddress中,类的名称也是属性的名称:

public class vmCompanyAddress
{
     public StatelyTechAdmin.Models.Company Company { get; set; }
Run Code Online (Sandbox Code Playgroud)

我将属性的名称更改为与类名不同的名称,并开始工作:

public class vmCompanyAddress
{
     public StatelyTechAdmin.Models.Company TheCompany { get; set; }
Run Code Online (Sandbox Code Playgroud)

  • 绝对点!非常感谢,非常感谢您为我调查此内容.我当然不会再犯同样的错误. (3认同)
  • 非常欢迎你.虽然编译器允许它,但我不是命名我的属性的忠实粉丝,就像它们被定义为的类名一样.我将类名视为保留字,因此在引用类与类的实例时应该没有混淆. (2认同)

Mar*_*sch 10

我们今天遇到了同样的问题.这个问题中接受的答案只是实际问题的一个肮脏的解决方法.

表单模型中的ClassName和PropertyName可以相同,模型绑定器中没有限制.限制是控制器中操作的参数.您不能将参数命名为表单模型中具有复杂类型的属性.导致绑定器尝试将HTTP POST表单值绑定company到控制器中的此参数.它不适合您,因为绑定器尝试将CompanyType 的值绑定 到CompanyAddresstype.

要解决您的问题,您只需将参数重命名companycompanyAddressModel- 或任何不属于您的模型类中的属性.

[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create(CompanyAddress company)
Run Code Online (Sandbox Code Playgroud)

改成:

[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create(CompanyAddress companyAddressModel)
Run Code Online (Sandbox Code Playgroud)

有关模型绑定的更多信息,请参见此处:http://aspnetmvc.readthedocs.org/projects/mvc/en/latest/models/model-binding.html

MVC将尝试按名称将请求数据绑定到操作参数.MVC将使用参数名称及其公共可设置属性的名称查找每个参数的值.[...]除了路由值之外,MVC还将绑定来自请求各个部分的数据,并按设定顺序进行绑定.下面是模型绑定查看它们的顺序中的数据源列表:

  • 表单值:这些是使用POST方法在HTTP请求中的表单值.
  • 路由值:路由提供的路由值集.
  • 查询字符串:URI的查询字符串部分.

ASP.NET WebAPI文档中的一个很好的例子,它使用相同的技术:

HttpResponseMessage Put(int id, Product item) { ... }
Run Code Online (Sandbox Code Playgroud)

这里的Id属性Product映射到id控制器中的参数.这将起作用,导致在操作中使用与模型类中相同的原始数据类型.