2009-06-05 6 views
6

J'ai une question sur la façon d'obtenir la fonctionnalité de liste blanche et noire du UpdateModel/TryUpdateModel du contrôleur MVC pour travailler sur les propriétés individuelles des objets enfants. Par exemple, disons que j'ai un questionnaire qui collecte des détails sur la personne qui remplit le formulaire et sur sa société.Comment faire pour mettre en liste blanche/liste noire les champs d'objet enfant dans la méthode ModelBinder/UpdateModel?

seraient nommés Ma forme [simplifié] champs, par exemple:

YourName 
YourEmail 
Company.Name 
Company.Phone 

Maintenant, dans mon modèle, permet de dire que je ne veux pas Company.ID ou Company.IsPremiumMember à trafiqués, donc je J'aimerais les exclure de la reliure. J'ai essayé une combinaison de listes blanches, de listes noires et des deux pour que cela fonctionne. Je n'ai pas eu de succès. Voici ce que je suis en cours d'exécution dans:

Quand j'intégriez explicitement dans mon whitelist les mêmes quatre fieldnames j'ai écrit ci-dessus, la société entière ne soit pas lié (c.-à-questionnaire.Company est nulle à gauche) à moins que je ajoute aussi « Société "dans ma liste blanche. Mais alors cela a l'effet indésirable de lier l'entreprise ENTIER, et pas seulement les deux propriétés que je veux.

Donc, j'ai ensuite essayé d'inclure Company.ID et Company.IsPremiumMember dans ma liste noire, mais cela semble être surpassé par la liste blanche et ne filtre pas ces propriétés "après coup", je suppose. Je sais qu'il existe d'autres façons d'exprimer la "capacité de liaison", comme par l'intermédiaire de l'attribut [Bind] sur les membres, mais ce n'est pas idéal car j'aimerais utiliser les mêmes classes de modèle dans d'autres situations avec différentes des règles contraignantes, telles que permettre à un administrateur de définir les propriétés souhaitées.

Je m'attends à une réponse évidente, c'est que je devrais écrire mon propre classeur modèle, et j'ai déjà commencé à essayer de voir comment faire peut-être cela, mais j'espérais vraiment utiliser un "out-of-the- box "solution pour ce qui (à mon avis) semble être un scénario très commun. Une autre idée que je réfléchis est de fabriquer mon propre dictionnaire ValueProvider pour le remettre à la méthode UpdateModel, mais encore une fois, quelque chose que je préfère éviter s'il y a un moyen plus facile.

Merci pour toute aide! -Mike


Addendum # 1

Voici les champs que je présente sur ma forme:

YourName 
YourEmail 
Company.Name 
Company.Phone

Et voici ce qu'un chapeau noir envoie mon chemin :

[email protected]&Company.Name=ACME+Corp&Company.Phone=555-555-5555&Company.CreditLimit=10000000

(! Assurez-vous que vous remarquez que le paramètre supplémentaire clouée là-bas à la fin)

Et voici le problème:

Comme je l'ai d'abord affiché, il ne semble pas possible (en utilisant le classeur de modèle par défaut) pour empêcher CreditLimit d'être défini --- c'est soit l'ensemble de la société ou rien --- sans une grande solution de contournement. Ai-je tort?


Addendum # 2

Je suis à peu près convaincu maintenant que l'objectif simple je n'est pas possible "de la boîte." Ma solution a été de parcourir les champs de formulaire affichés et de construire mon propre dictionnaire ValueProvider, en mettant ainsi en liste blanche les champs que je veux autoriser, et en les transmettant à UpdateModel.


Addendum # 3

Je n'ai toujours pas encore vérifié AutoMapper, mais avec quelque chose comme ça à la main, la solution de créer des ViewModels/DTO pour gérer ce type de complexe whitelisting- --plus la possibilité d'attacher facilement la même validation côté serveur (FluentValidation) que j'utilise déjà sur les objets de mon domaine --- semble une solution viable. Merci tout le monde!

Répondre

1

En général, la meilleure façon de faire est de créer vue-modèles, les modèles construits spécialement pour votre point de vue. Ces modèles sont et non objets de domaine. Ce sont des objets de transfert de données, conçus pour transférer des données de vos actions de contrôleur vers vos modèles de vue. Vous pouvez utiliser un outil comme AutoMapper sans effort pour créer/mettre à jour un objet de modèle de domaine à partir de votre objet view-model ou pour créer/mettre à jour un objet view-model à partir de votre modèle de domaine.

+0

AutoMapper ressemble à un excellent utilitaire qui simplifierait vraiment cela. Je vais vérifier plus tard ce soir. Merci! – Funka

+1

J'ai également trouvé que UpdateModel vient sous une forme générique, UpdateModel , que j'ai trouvé sur un autre post ici à S.O. cela recommande de créer une interface T qui peut agir comme une liste blanche. Je n'ai vu cette technique dans aucun des livres MVC que j'ai lus, mais il semble que cela pourrait avoir une certaine promesse. (Peut-être pas plus d'effort que de créer une poignée de DTO.) P.S. cet autre poste, je référencé est ici: http://stackoverflow.com/questions/924424/difference-using-updatemodel-and-modelbinding-in-parameter – Funka

+0

Si vous utilisez le modèle de vue-modèle, vous pouvez également effectuer server- puissant validation latérale sur le modèle de vue strictement typé (au lieu des champs Request.Form ou FormCollection) en utilisant des bibliothèques telles que Castle.Components.Validator ou FluentValidation. – yfeldblum

1

Je travaille autour de ce problème en faisant l'action d'accepter deux objets (le parent et l'objet enfant)

Exemple:
Supposons que nous avons le modèle suivant:

public class Employee 
    { 
     public string Name { get; set; } 
     public int Age { get; set; } 
     public Company Comapany { get; set; } 
    } 
    public class Company 
    { 
     public int Phone { get; set; } 
    } 

Vous construisez votre former comme ceci:

<form action="Home/Create" method="post"> 
    <label for="Employee.Name">Name</label> 
    <%=Html.TextBox("Employee.Name") %><br /> 
    <label for="Employee.Name">Age</label>  
    <%=Html.TextBox("Employee.Age") %><br /> 
    <label for="Employee.Name">Comapany Phone</label>  
    <%=Html.TextBox("Company.Phone") %><br /> 
    <input type="submit" value="Send" /> 
    </form> 

Ensuite, créez une action "Créer" qui accepte deux objets un de type Employ ee et l'autre de type Comapny et affecter l'objet Société à la propriété Employee.Company dans l'action:

public ActionResult Create(Employee employee,Company company) 
     { 
      employee.Comapany = company; 
      UpdateModel(employee); 
      return View(); 
     } 

J'espère que cela vous aide.

Edit:

public ActionResult Create(Employee employee,Company company) 
{ 
    employee.Comapany = company; 
    UpdateModel(employee,new[] {"Name","Email","Phone"}); 
    return View(); 
} 
+0

Merci votre réponse.Cependant, je n'ai aucun problème pour lier le modèle: mon problème est d'essayer de restreindre ce qui dans le modèle est lié. Il semble que dans votre exemple, sans fournir de liste blanche ou de liste noire (ou autre équivalent) à la méthode UpdateModel, quelqu'un pourrait encore configurer Company.IsPremiumMember en l'injectant dans son post de formulaire. – Funka

+0

Ensuite, la solution consiste à transmettre la liste des propriétés que vous souhaitez inclure à la méthode UpdateModel. Je vais mettre à jour ma réponse –

+0

J'ai ajouté un addendum à mon article original. (Voir en particulier la dernière ligne.) Le problème ressemble plus à un "tout ou rien" sur la propriété de la Société ... – Funka

0

Avez-vous essayé d'utiliser ce qui suit ?:

public ActionResult Créer ([Bind (Exclure = "PropertyToExclude1, PropertyToExclude2")] employé de l'employé) {

// code d'action ici

}

ou utilisez Inclure au lieu d'Exclure pour Liste les champs qui peuvent être liés plutôt que ceux qui ne peuvent pas

+0

Bonjour, comme indiqué Dans mon post original, le problème n'est pas que je ne peux pas exclure "PropertyToExclude1". Le problème est que je ne peux pas exclure "SomeParent.SomeProperty" de cette manière. – Funka

+0

Quel gâchis .... – Aaron

Questions connexes