2014-05-13 117 views
6

我通過窗體HttpPost從視圖傳回ViewModel到控制器。但是,返回的值始終爲NULL。MVC視圖ViewModel HttpPost返回值始終爲NULL

視圖模型

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

    public SelectList Counties { get; set; } 
} 

公司類模型

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

公司地址類模型

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

控制器(獲得):

// 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); 
    } 

控制器(後):

[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); 
    } 

視圖(創建)

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

任何人都可以請提供任何意見,以爲什麼當所有字段被填充時,我的返回ViewModel值爲NULL?

我已使用網絡記錄功能在Google Chrome瀏覽器中進行了檢查,並且所有值均以JSON格式發回。

非常感謝。

------------編輯---------------

這裏有什麼我可以從谷歌Chrome網絡看到部分監控

Company.Name:ABC123 Company.CreatedDate:2014年5月13日00:00:00 ....

所以肯定是被退回了。

+0

夠搞怪,有人已經有過類似的問題,與回發 「Company.Name」。對於funsies,請嘗試刪除該字段並查看它是否仍將所有內容都回傳爲空。 http://stackoverflow.com/questions/780026/asp-net-mvc-model-binding-returning-null-values –

+1

CompanyAddressTypeId拼寫錯誤。另外,嘗試像這樣定義你的表單 - Html.BeginForm(「yourControllerNameHere」,「Create」,FormMethod.Post) – JB06

+0

謝謝@ErikElkins然而,從我的View中刪除Company.Name並沒有什麼區別。一切仍然回傳爲NULL。 – RobHurd

回答

11

我能夠重現您的問題,並且感到困惑,因爲我知道默認的MVC Model Binder可以理解複雜的類型。我剝去了大部分代碼,只是試圖用公司對象來完成,但仍然失敗。然後我注意到,在vmCompanyAddress該類的名稱也是屬性的名稱:

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

我換了名稱的屬性的東西從類名稱不同,它開始工作:

public class vmCompanyAddress 
{ 
    public StatelyTechAdmin.Models.Company TheCompany { get; set; } 
+3

絕對正確!非常感謝,非常感謝您爲我進行調查。我當然不會再犯同樣的錯誤。 – RobHurd

+2

非常歡迎。儘管編譯器允許,但我並不喜歡將它們的屬性命名爲它們所定義的類名稱。我將類名稱視爲保留字,因此在引用類和類的實例時應該不會造成混淆。 –

2

自己沒有嘗試過,但很久以前就有很多類似的問題,我用自定義的ModelBinder解決:我不推薦。

我猜你的數據看起來不像:{公司:{...},地址:{...}}?

我認爲解決方案是讓MVC使用模板和EditorFor()來理解數據的結構。例如http://lostechies.com/jimmybogard/2011/09/07/building-forms-for-deep-view-model-graphs-in-asp-net-mvc/就是一個很好的例子!

+0

感謝您的輸入。 @MatthewAtCriticalCogni擊中了頭部。我的ViewModel屬性被命名爲我的類相同,從而導致它失敗。 – RobHurd

10

今天我們遇到了同樣的問題。在這個問題上接受的答案只是對實際問題的一個骯髒的解決方法。

表單模型中的ClassName和PropertyName可以是相同的,模型聯編程序中沒有限制。限制是控制器中操作的參數。您不能將該參數命名爲表單模型中具有複雜類型的屬性。導致活頁夾將嘗試將HTTP POST表單值company綁定到控制器中的此參數。它不適用於您,因爲活頁夾嘗試將Company類型的值綁定到CompanyAddress類型。

要解決您的問題,您只需將參數company重命名爲companyAddressModel或任何不屬於模型類中的屬性。

[HttpPost] 
[ValidateAntiForgeryToken] 
public ActionResult Create(CompanyAddress company) 

變化:

[HttpPost] 
[ValidateAntiForgeryToken] 
public ActionResult Create(CompanyAddress companyAddressModel) 

在這裏看到更多有關模型綁定:http://aspnetmvc.readthedocs.org/projects/mvc/en/latest/models/model-binding.html

MVC將嘗試通過名稱將請求數據綁定到行動參數。 MVC將使用參數名稱 及其公共可設置屬性的名稱查找每個參數的值。 除路由值 MVC將從請求的各個部分綁定數據,並且它在 中按設定的順序綁定數據。下面是在訂單數據源列表, 模型通過它們結合的外觀:

  • 表單值:這些是去使用POST方法的HTTP請求表單值。
  • 路由值:由路由提供的一組路由值。
  • 查詢字符串:URI的查詢字符串部分。

ASP.NET WebAPI documentation一個很好的例子,這是使用相同的技術:

HttpResponseMessage Put(int id, Product item) { ... } 

這裏ProductId屬性被映射到在控制器中的id參數。這將起作用,導致在動作中使用與在模型類中相同的基本數據類型。

2

確保您的ViewModel暴露屬性而不僅僅是字段。

這工作:

public DAL.Models.Account acct {get;set;} 

這不:

public DAL.Models.Account acct;