2014-05-13 2 views
6

Je passe un ViewModel de ma vue au contrôleur via un formulaire HttpPost. Cependant, les valeurs renvoyées sont toujours NULL.MVC View ViewModel HttpPost la valeur de retour est toujours NULL

ViewModel

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

    public SelectList Counties { get; set; } 
} 

Modèle Société Classe

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

companyAddress Classe Modèle

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

Controller (get):

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

Controller (post):

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

View (créer)

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

Quelqu'un peut-il s'il vous plaît offrir des conseils à pourquoi mes valeurs ViewModel de retour sont NULL lorsque tous les champs sont remplis?

J'ai vérifié dans le navigateur Google Chrome en utilisant la fonction d'enregistrement réseau et toutes les valeurs sont affichées au format JSON.

Merci beaucoup.

------------ --------------- EDIT

Voici une partie de ce que je peux voir à partir du réseau Google Chrome surveiller

Company.Name:ABC123 Company.CreatedDate: 13/05/2014 00:00:00 ....

il est certainement retourné.

+0

assez drôle, quelqu'un a eu un problème similaire avec l'affichage de retour "Company.Name". Pour les funsies, essayez de supprimer ce champ et voyez s'il publie toujours tout ce qui est nul. http://stackoverflow.com/questions/780026/asp-net-mvc-model-binding-returning-null-values ​​ –

+1

CompanyAddressTypeId est mal orthographié. Aussi, essayez de définir votre formulaire comme ceci - Html.BeginForm ("yourControllerNameHere", "Create", FormMethod.Post) – JB06

+0

Merci @ErikElkins cependant, supprimer Company.Name de ma vue n'a pas fait de différence. Tout est toujours comptabilisé comme NULL. – RobHurd

Répondre

11

J'ai été capable de reproduire votre problème et j'étais confus car je sais que le classeur MVC par défaut comprend les types complexes. J'ai enlevé la plus grande partie du code et j'ai juste essayé de le faire avec l'objet Company, qui a quand même échoué.Je me suis alors remarqué que, dans vmCompanyAddress que le nom de la classe était aussi le nom de la propriété:

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

J'ai changé le nom de la propriété à quelque chose de différent du nom de la classe et il a commencé à travailler:

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

Absolument sur! Merci beaucoup, j'apprécie vraiment que vous regardiez cela pour moi. Je ne referai certainement pas la même erreur. – RobHurd

+2

Vous êtes les bienvenus. Bien que le compilateur le permette, je ne suis pas un grand fan de nommer mes propriétés de la même manière que le nom de classe pour lequel elles sont définies. Je vois les noms de classe comme des mots réservés et ne devrait donc pas être une source de confusion lorsque je référence la classe à une instance de la classe. –

2

N'avez pas essayé moi-même mais j'ai eu beaucoup de problèmes similaires il y a longtemps que j'ai résolu avec CustomBinder: s que je ne recommande pas.

Je suppose que vos données ne ressemblent pas à: {Société: {...}, Adresse: {...}}?

Je pense que la solution est d'avoir MVC pour comprendre la structure des données en utilisant des modèles et EditorFor(). Voir http://lostechies.com/jimmybogard/2011/09/07/building-forms-for-deep-view-model-graphs-in-asp-net-mvc/ pour un bon exemple!

+0

Merci pour l'entrée. @MatthewAtCriticalCogni a frappé le clou sur la tête. Ma propriété ViewModel a été nommée la même que ma classe, provoquant ainsi son échec. – RobHurd

10

Nous avons eu le même problème aujourd'hui. La réponse acceptée dans cette question est seulement une solution de contournement sale pour le problème réel.

ClassName et PropertyName dans un modèle de formulaire peuvent être les mêmes, il n'y a aucune limitation dans le classeur de modèle. La limitation est le paramètre de l'action dans votre contrôleur. Vous ne devez pas nommer le paramètre comme une propriété avec un type complexe dans votre modèle de formulaire. Cause le classeur va essayer de lier la valeur de formulaire HTTP POST de company à ce paramètre dans votre contrôleur. Cela ne fonctionnera pas pour vous, car le classeur tente de lier les valeurs d'un type Company au type CompanyAddress.

Pour résoudre votre problème, vous devez simplement renommer le paramètre company en companyAddressModel - ou tout ce qui n'est pas une propriété de votre classe de modèle.

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

changement:

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

Voir ici pour plus d'informations sur le modèle de liaison: http://aspnetmvc.readthedocs.org/projects/mvc/en/latest/models/model-binding.html

MVC va essayer de lier les données de demande à l'action paramètres par nom. MVC recherchera des valeurs pour chaque paramètre en utilisant le nom de paramètre et les noms de ses propriétés définissables par le public. [...] En plus des valeurs de route MVC lie les données à partir de diverses parties de la demande et il le fait dans un ordre défini. Voici une liste des sources de données dans l'ordre regards contraignant modèle à travers eux:

  • VALUES: Ce sont des valeurs de forme qui vont dans la requête HTTP en utilisant la méthode POST.
  • Valeurs d'itinéraire: Ensemble de valeurs d'itinéraire fournies par routage.
  • Chaînes de requête: partie de chaîne de requête de l'URI.

Un bon exemple de ASP.NET WebAPI documentation, qui utilise la même technique:

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

Voici la propriété Id de Product est mis en correspondance avec le paramètre id dans le contrôleur. Ce qui fonctionnera, car dans l'action, le même type de données primitif est utilisé que dans la classe du modèle.

2

Assurez-vous que votre ViewModel expose des propriétés et pas seulement des champs.

Cela fonctionne:

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

Cela ne signifie pas:

public DAL.Models.Account acct; 
Questions connexes