J'ai une structure d'objet de modèle avec une classe Foo
qui contient une Bar
avec une valeur de chaîne.
public class Foo
{
public Bar Bar;
}
public class Bar
{
public string Value { get; set; }
}
Et un modèle de vue qui utilise cette structure comme celle-ci
public class HomeModel
{
public Foo Foo;
}
J'ai alors un formulaire en vue qui dans Razor ressemble à ceci.
<body>
<div>
@using (Html.BeginForm("Save", "Home", FormMethod.Post))
{
<fieldset>
@Html.TextBoxFor(m => m.Foo.Bar.Value)
<input type="submit" value="Send"/>
</fieldset>
}
</div>
</body>
En html ça devient.
<form action="/Home/Save" method="post">
<fieldset>
<input id="Foo_Bar_Value" name="Foo.Bar.Value" type="text" value="Test">
<input type="submit" value="Send">
</fieldset>
</form>
Enfin, le contrôleur pour gérer les post-loos comme ceci
[HttpPost]
public ActionResult Save(Foo foo)
{
// Magic happends here
return RedirectToAction("Index");
}
Mon problème est que Bar
dans Foo
est null
une fois que l'action Save
est effectuée (Foo
est créé mais avec un champ null
Bar
).
Je pensais que le classeur de modèle dans MVC serait capable de créer les objets Foo
et Bar
et de définir la propriété Value
tant qu'elle ressemble à ce qui est décrit ci-dessus. Qu'est-ce que je rate?
Je sais aussi que mon modèle de vue est un peu trop compliqué et pourrait être plus simple, mais je voudrais vraiment m'aider si je pouvais utiliser la structure d'objet plus profonde. Les exemples ci-dessus utilisent ASP.NET 5.
Premièrement, la variable DefaultModelBinder
ne sera pas liée aux champs, vous devez donc utiliser des propriétés.
public class HomeModel
{
public Foo Foo { get; set; }
}
Deuxièmement, les assistants génèrent des contrôles basés sur HomeModel
mais vous enregistrez à nouveau vers Foo
. Changez la méthode POST pour
[HttpPost]
public ActionResult Save(HomeModel model)
ou utilisez la variable BindAttribute
pour spécifier la variable Prefix
(qui supprime essentiellement la valeur du préfixe des valeurs publiées - pour que Foo.Bar.Value
devienne Bar.Value
aux fins de la liaison)
[HttpPost]
public ActionResult Save([Bind(Prefix="Foo")]Foo model)
Notez également que vous ne devez pas nommer le paramètre de méthode avec le même nom que l'une de vos propriétés, sinon la liaison échouera et votre modèle sera null.
Je viens de découvrir une autre raison qui peut arriver, c'est-à-dire si votre propriété est nommée Settings
! Considérez le modèle de vue suivant:
public class SomeVM
{
public SomeSettings DSettings { get; set; } // named this way it will work
public SomeSettings Settings { get; set; } // property named 'Settings' won't bind!
public bool ResetToDefault { get; set; }
}
Dans le code, si vous vous liez à la propriété Settings
, la liaison n'est pas établie (pas seulement lors de la publication, mais même lors de la génération du formulaire). Si vous renommez Settings
en DSettings
(etc.), cela fonctionne à nouveau soudainement.
J'avais le même problème et après avoir suivi les étapes de @Stephen Muecke, j'ai réalisé que le problème était dû à la désactivation de mes entrées (je les désactivais avec JQuery sur document prêt), comme vous pouvez le voir ici: Comment envoyer des informations désactivées entrée dans ASP.NET MVC? . À la fin, j'ai utilisé l'attribut désactivé en lecture seule au lieu de l'attribut désactivé et toutes les valeurs ont été envoyées avec succès au contrôleur.
J'ai eu le même problème, mais une fois que j'ai créé un HIDDEN FIELD pour la clé étrangère ... tout a bien fonctionné ...
EXEMPLE DE FORME:
@using (Html.BeginForm("save", "meter", FormMethod.Post))
{
@Html.AntiForgeryToken()
@Html.ValidationSummary(true)
@Html.HiddenFor(model => Model.Entity.Id)
@Html.HiddenFor(model => Model.Entity.DifferentialMeter.MeterId)
@Html.HiddenFor(model => Model.Entity.LinearMeter.MeterId)
@Html.HiddenFor(model => Model.Entity.GatheringMeter.MeterId)
... all your awesome controls go here ...
}
EXEMPLE D'ACTION:
// POST: /Meter/Save
[HttpPost]
public ActionResult Save(Meter entity)
{
... world-saving & amazing logic goes here ...
}