Willkommen auf myCSharp.de! Anmelden | kostenlos registrieren
 | Suche | FAQ

Hauptmenü
myCSharp.de
» Startseite
» Forum
» Suche
» Regeln
» Wie poste ich richtig?

Mitglieder
» Liste / Suche
» Wer ist online?

Ressourcen
» FAQ
» Artikel
» C#-Snippets
» Jobbörse
» Microsoft Docs

Team
» Kontakt
» Cookies
» Spenden
» Datenschutz
» Impressum

  • »
  • Community
  • |
  • Diskussionsforum
ASP.NET MVC 2: Model Binding mit [Bind]
m0rius
myCSharp.de - Member

Avatar #avatar-3125.png


Dabei seit:
Beiträge: 1043

Themenstarter:

ASP.NET MVC 2: Model Binding mit [Bind]

beantworten | zitieren | melden

Hallo,

um zu vermeiden, dass beim Model Binding von ASP.NET MVC 2 per [Bind] Eigenschaften gebunden werden, die nicht gebunden werden sollen, schränke ich diese wie folgt ein:

[MetadataType(typeof(Dinner_Validation))]
[Bind(Include = "Title,Description,EventDate,Address,Country,ContactPhone,Latitude,Longitude")]
public partial class Dinner
{
    /* ... */
}
Der Nachteil ist, dass die Eigenschaften hier nicht umbenannt werden, sobald ich diese an einer anderen Stelle per Refactor => Rename... umbenenne. Das führt zu schwer aufzufindenden Bugs, wenn sich bestimmte Formularfelder nicht mehr editieren lassen, weil die zugehörige Eigenschaft umbenannt wurde.

Gibt es – neben Alternativen wie ViewModels etc. – für diese Art der Beschränkung eine Lösung für das Problem?

m0rius
Mein Blog: blog.mariusschulz.com
Hochwertige Malerarbeiten in Magdeburg und Umgebung: M'Decor, Ihr Maler für Magdeburg
private Nachricht | Beiträge des Benutzers
Peter Bucher
myCSharp.de - Experte

Avatar #jVxXe7MDBPAimxdX3em3.jpg


Dabei seit:
Beiträge: 6141
Herkunft: Zentralschweiz

beantworten | zitieren | melden

Salute m0rius

Wieso machst du kein "Exclude"?
Also Black- anstelle von Whitelisting.


Gruss Peter
--
Microsoft MVP - Visual Developer ASP / ASP.NET, Switzerland 2007 - 2011

- https://peterbucher.ch/ - Meine persönliche Seite
- https://fpvspots.net/ - Spots für FPV Dronenflüge
private Nachricht | Beiträge des Benutzers
m0rius
myCSharp.de - Member

Avatar #avatar-3125.png


Dabei seit:
Beiträge: 1043

Themenstarter:

beantworten | zitieren | melden

Hallo Peter Bucher,

weil dadurch mein Problem weiterhin besteht. So würde ich mir eher noch eine zusätzliche Sicherheitslücke (Tampering) einholen, wenn ich beispielsweise die Eigenschaft Id vom Binding ausschließe, die in einem Refactoring zu DinnerID umbenannt wird.

m0rius
Mein Blog: blog.mariusschulz.com
Hochwertige Malerarbeiten in Magdeburg und Umgebung: M'Decor, Ihr Maler für Magdeburg
private Nachricht | Beiträge des Benutzers
VizOne
myCSharp.de - Member

Avatar #avatar-1563.gif


Dabei seit:
Beiträge: 1551

beantworten | zitieren | melden

Hi m0rius,

Getrennte ViewModels haben natürlich Vor- und Nachteile, siehe hier: http://geekswithblogs.net/michelotti/archive/2009/10/25/asp.net-mvc-view-model-patterns.aspx

Wenn du keine getrennten ViewModels haben willst, hier eine Alternative: Erstelle eine Basisklasse für Dinner (z.B. BindableDinner), die alle Eigenschaften enthält, die du binden möchtest. Im Controller benutzt du dann TryUpdateModel oder UpdateModel wie folgt:


public ActionResult MeineAction(Dinner input){
  Dinner data =  /* aus DB oder ähnlich */
  
  // nur die Properties von BindableDinner binden:
  if(TryUpdateModel<BindableDinner>(data)){
     // alles ok
  } 
}

Damit kannst du ohne Strings und refactoringsicher Attribute vom Binding ausschließen.

Das ganze geht statt mit einer Basisklasse auch mit interfaces. Details siehe hier: http://www.dotnetcurry.com/ShowArticle.aspx?ID=439

Statt UpdateModel könntest du auch BindableDinner als Parameter akzeptieren, das Model validieren und dann das Mapping zum echten Model mittels AutoMapper vornehmen.


public ActionResult MeineAction(BindableDinner input){

  Dinner data = /* aus DB oder ähnlich */
  if(ModelState.IsValid){
    Mapper.Map(input, data);
    // alles klar!
  }
}

Hierbei muss Dinner natürlich nicht mal von BindableDinner erben, womit wir quasi wieder beim ViewModel wären.

Noch eine Alternative, ohne BindableDinner: du erstellst die Liste der zu inkludierenden Properties mittels Lambaausdrücken und gibst diese Liste an UpdateModel weiter:


public class Dinner {
  public static readonly string[] BindableProperties;

  static Dinner(){
    BindableProperties= new []{
     PropertyName<Dinner>(x=>x.Title),
     PropertyName<Dinner>(x=>x.Description), 
    // usw.
    };
  }

  static string PropertyName<T>(Expression<Func<T, object>> expr) {
    var member = expr.Body as MemberExpression;
    return member.Member.Name;
  }
}

// 

public ActionResult MeineAction(){
  Dinner dinner = /* aus DB */
  if(TryUpdateModel(dinner, Dinner.BindableProperties)){
    // okidoki
  }
  ...
}
  

Das ist ebenfalls 100%ig refactoringsicher.

So viel zu meinen Vorschlägen. Aber wie gesagt, ein reines ViewModel ist auch eine Alternative, wenn auch mit den bekannten Problemen (v.a. Code-Duplikation).

Grüße,
Andre
private Nachricht | Beiträge des Benutzers
m0rius
myCSharp.de - Member

Avatar #avatar-3125.png


Dabei seit:
Beiträge: 1043

Themenstarter:

beantworten | zitieren | melden

Hallo VizOne,

vielen Dank für deine ausführliche Antwort! Ich werde wahrscheinlich die Binding-Basisklasse umsetzen, da mir die Gefahr bei mehreren Entwicklern zu hoch ist, dass vergessen wird, die Include-Liste anzupassen.

m0rius
Mein Blog: blog.mariusschulz.com
Hochwertige Malerarbeiten in Magdeburg und Umgebung: M'Decor, Ihr Maler für Magdeburg
private Nachricht | Beiträge des Benutzers
VizOne
myCSharp.de - Member

Avatar #avatar-1563.gif


Dabei seit:
Beiträge: 1551

beantworten | zitieren | melden

Natürlich gibt es noch eine Möglichkeit, die Implementierung eines eigenen IModelBinder, ggf. auf Basis des DefaultModelBinders. Damit kannst du das dann vollkommen transparent machen.

Idealerweise führst du dafür ein Attribut ein (DontBindAttribute oder ähnlich), dass dein Modelbinder dann verwendet, um Eigenschaften zu ignorieren. Überhaupt merkwürdig, dass das noch existiert (oder habe ich was übersehen?).
private Nachricht | Beiträge des Benutzers