2010-02-06 15 views
18

Edit: Hinzugefügt Prämie, weil ich eine MVC3 Lösung bin der Suche nach anderen als diese (falls vorhanden):Warum kümmert sich ASP.NET MVC um meine schreibgeschützten Eigenschaften während der Datenbindung?

DataAnnotationsModelValidatorProvider.AddImplicitRequiredAttributeForValueTypes = false;


Ich habe eine Nur-Lese-Eigenschaft auf meinem ‚Adresse‘ Modell 'CityStateZip'.

Es ist nur eine bequeme Möglichkeit, Stadt, Staat, PLZ von einer US-Adresse zu bekommen. Es wird eine Ausnahme ausgelöst, wenn das Land nicht USA ist (der Anrufer soll zuerst prüfen).

public string CityStateZip 
    { 
     get 
     { 
      if (IsUSA == false) 
      { 
       throw new ApplicationException("CityStateZip not valid for international addresses!"); 
      } 

      return (City + ", " + StateCd + " " + ZipOrPostal).Trim().Trim(new char[] {','}); 
     } 
    } 

Dies ist Teil meines Modells, so dass es gebunden wird. Vor ASP.NET MVC2 RC2 verursachte dieses Feld während der Datenbindung nie ein Problem. Ich habe nie wirklich darüber nachgedacht - schließlich ist es nur lesbar.

Jetzt, mit der RC2-Version vom Januar 2010, gibt es einen Fehler beim Datenbinding - weil der Standardmodellbinder diesen Wert überprüfen möchte (obwohl er schreibgeschützt ist).

Es ist die Zeile 'base.OnModelUpdated', die zur Auslösung dieses Fehlers führt.

public class AddressModelBinder : DefaultModelBinder 
{ 
    protected override void OnModelUpdated(ControllerContext controllerContext, ModelBindingContext bindingContext) 
    { 
     base.OnModelUpdated(controllerContext, bindingContext); 

Last-Minute-Änderungen an den Modelbinder offenbar diese Änderung im Verhalten verursacht - aber ich bin ich noch nicht ganz sicher, was die repurcussions davon sind - oder ob dies ist ein Bug? Ich gebe das an das MVC-Team weiter, bin aber gespannt, ob jemand sonst in der Zwischenzeit irgendwelche Vorschläge hat, wie ich verhindern kann, dass diese Eigenschaft bindet.

Dieser Artikel ist es wert, über die Änderungen gelesen zu werden - erwähnt aber keine schreibgeschützten Eigenschaften (nicht, dass ich das erwarten würde). Das Problem (falls es eines gibt) kann breiter sein als diese Situation - ich bin mir nicht sicher, ob es irgendwelche Rückwirkungen gibt - wenn überhaupt!

Input Validation vs. Model Validation in ASP.NET MVC


Wie die stacktrace hier @haacked angefordert:

ich diese erhalten, indem einfach die folgende Zeile zu jedem Modell hinzugefügt und einen Beitrag zu der entsprechenden Aktionsmethode zu machen. In diesem Fall habe ich es meinem einfachsten möglichen Modell hinzugefügt.

public string Foo { get { throw new Exception("bar"); } } 

[TargetInvocationException: Eigenschaftenaccessor 'Foo' auf dem Objekt 'Rolling_Razor_MVC.Models.ContactUsModel' warf die folgende Ausnahme: 'bar'] System.ComponentModel.ReflectPropertyDescriptor.GetValue (Object-Komponente) + 390 System.Web.Mvc. < > c__DisplayClassb. <GetPropertyValueAccessor> b__a() +18 System.Web.Mvc.ModelMetadata.get_Model() +22 System.Web.Mvc.ModelMetadata.get_RealModelType() +29 System.Web.Mvc. <GetValidatorsImpl> d__0.MoveNext() +38 System.Linq. <SelectManyIterator> d__14`2.MoveNext() +273 System.Web.Mvc. < Bestätigen Sie > d__5.Movenext() 644 System.Web.Mvc.DefaultModelBinder.OnModelUpdated (Controllercontroller, ModelBindingContext Binding) +92 System.Web.Mvc.DefaultModelBinder.BindComplexElementalModel (Controllercontroller, ModelBindingContext Binding, Object Model) +60 System.Web .Mvc.DefaultModelBinder.BindComplexModel (ControllerContext controllerContext, ModelBindingContext bindingContext) +1048 System.Web.Mvc.DefaultModelBinder.BindModel (ControllerContext controllerContext, ModelBindingContext bindingContext) +280 System.Web.Mvc.Controller.TryUpdateModel (TModel-Modell, String-Präfix , String [] includeProperties, Zeichenfolge [] excludeProperties, IValueProvider valueProvider) +449 System.Web.Mvc.Controller.TryUpdateModel (TModel-Modell) +73

+0

Was Global.asax.cs folgendes hinzufügen müssen, um zu bekommen ist Der genaue Fehler, den Sie sehen? Es wäre auch hilfreich, den entsprechenden Controller und den Code zu sehen. –

+0

Wir brauchen mehr Details, aber meine Vermutung ist IsUsa ist falsch, wenn wir versuchen, diese Eigenschaft zu lesen, wodurch eine Ausnahme ausgelöst wird. Nicht sicher, warum wir es während der Modellbindung lesen würden, außer es gibt ein Formularfeld namens "CityStateZip" in dem Formular, das gepostet wird. – Haacked

+0

@brad der genaue Fehler ist 'CityStateZip nicht gültig für internationale Adressen!' ;-) Ich aktualisiere die Frage mit dem vollen Stack-Trace. zu duplizieren, fügen Sie dies einfach zu jedem bestehenden Modell, das Sie haben, und einen POST zu der entsprechenden Aktionsmethode: öffentlichen String Foo {get {neue Ausnahme werfen ("bar"); }} –

Antwort

16

Ich glaube, ich habe ein ähnliches Problem.

http://forums.asp.net/t/1523362.aspx


bearbeiten:: Ich habe die Details veröffentlicht Antwort von MVC-Team (von oben URL):

Wir dies untersucht und zu dem Schluss gekommen, dass das Validierungssystem verhält sich wie erwartet. Da bei der Modellvalidierung versucht wird, die Validierung für alle Eigenschaften auszuführen, und da nicht-nullbare Werttypeigenschaften ein implizites Attribut [Erforderlich] aufweisen, validieren wir diese Eigenschaft und rufen dabei ihren Getter auf. Wir verstehen, dass dies eine bahnbrechende Änderung gegenüber V1 des Produkts ist, aber es ist notwendig, dass das neue Modellvalidierungssystem korrekt funktioniert.

Sie haben ein paar Möglichkeiten, um dies zu umgehen. Eine davon sollte funktionieren:

  • Ändern Sie die Date-Eigenschaft in eine Methode anstelle einer Eigenschaft; Auf diese Weise wird es vom MVC-Framework ignoriert.
  • Ändern Sie den Eigenschaftstyp in DateTime? anstelle von DateTime. Dies entfernt das implizite [Erforderlich] von dieser Eigenschaft.
  • Löschen Sie das statische DataAnnotationsModelValidatorProvider.AddImplicitRequiredAttributeForValueTypes-Flag. Dadurch wird das implizite [Erforderlich] aus allen nicht nullenbaren Werttypeigenschaften anwendungsweit entfernt. Wir überlegen, in V3 des Produkts ein Attribut hinzuzufügen, das uns signalisieren wird: "Binden Sie es nicht, validieren Sie es nicht, geben Sie einfach vor, dass diese Eigenschaft nicht existiert."

Nochmals vielen Dank für den Bericht!

+0

Überprüfen Sie die Antwort auf den obigen Beitrag. – Rudy

+1

zwei Dinge, die dies nicht anspricht, ist die Tatsache, dass mein Eigentum nur gelesen wurde, so dass es nicht einmal "bekommen" muss. Diese Lösung bringt mein Design etwas durcheinander, aber die Problemumgehungen funktionieren immer noch.Die zweite Sache ist, dass dies mit einer Ausnahme sowieso explodiert. das ist definitiv nicht gut. Wenn das Modell ausfällt, schlägt das Modell fehl, aber das Sprengen ist nicht gut –

+0

Ich habe genau das gleiche Problem, lesen Sie bitte meine Antwort Post mit Link, wenn Sie möchten. ich bin gespannt auf mvc v3, da es einfach zu viele ungelöste/fehlende elemente in v2 gibt, einschließlich dieser und der möglichkeit, mehrere sichten zur aktualisierung verschiedener physischer bereiche einer webpage, besserer benutzer serverseitiger validierungsunterstützung, etc etc zurückgeben zu können Umgehen Sie diese Probleme im Moment, aber nur so durch die Verwendung von "Hacks" und ich fühle nicht die Eleganz der Codierung, die ich mit mvc fühlen sollte; (Ich kann nicht auf v3 warten. –

0

Natürlich könnte ich CityStateZip zu GetCityStateZip() konvertieren, aber dann kann ich es in etwas wie silverlight nicht ganz so leicht binden. Dies könnte für eine temporäre Lösung für andere Personen funktionieren, bei denen dieses Problem auftritt.

0

ICH HABE DAS GENAUE PROBLEM !!

Weitere Informationen über mein Problem, können Sie besuchen ASP.NET MVC 2.0 Unused Model Property being called when posting a product to the server?

bedeutet das wir brauchen, um unsere Eigenschaften mit der Annahme programmieren, dass sie unerwartet genannt werden (vor Eigenschaften, die es hängt davon ab, eingerichtet sind/initialisiert etc) ... wenn das so ist, stellt dies eine Änderung in unseren Programmierpraktiken dar und ich würde gerne wissen, wie es weitergeht.

unterdessen habe ich nur eine einfache 'Wenn'-Prüfung, die das Problem beseitigt.

+1

im Allgemeinen Eigenschaften sollen genau das sein Wenn du zu viel Geschäftslogik drin hast, dann wirst du eine Änderung vornehmen müssen, aber du solltest es vielleicht sowieso tun. Es ist eine Schande, dass sie keine Eigenschaft hinzufügen können, die "validiere", aber vielleicht wird das kommen für MVC3 –

2

Immer noch das gleiche Problem mit MVC3.

Ich denke, der beste Weg, um nur diese in global.asax ist (von SevenCentral Antwort):

DataAnnotationsModelValidatorProvider.AddImplicitRequiredAttributeForValueTypes = false; 

Das ist für alle von ihnen deaktivieren wird

0

ich ein ähnliches Problem hatte, ein Feld, für das ich keine Validierung erwartete, erhielt einen Fehler, wenn das Formular an den Controller zurückgeschickt wurde. Nach einigem googlen stieß ich auf http://codeblog.shawson.co.uk/mvc-strongly-typed-view-returns-a-null-model-on-post-back/, wo es darauf hingewiesen wurde, dass Namenskonflikte Probleme verursachen könnten.

Obwohl ich nicht dachte, dass meine Post-Back-Variablenklasse widersprüchliche Eigenschaftsnamen hatte, löste das Umbenennen der Eigenschaft, die den Fehler erhielt, mein Problem.

1

Das sieht für die ganze Welt wie ein Fehler für mich aus. Ich kann völlig nicht verstehen, warum der ModelBinder meine Read-Only-Eigenschaften überprüfen muss (es mag einige technische Details geben, aber ich verstehe das definitiv nicht und bin nicht bereit, die Zeit dafür zu verschwenden).

Ich habe folgendes Modell Meta Data Provider in meiner Lösung rund um das Problem

protected override CachedDataAnnotationsModelMetadata CreateMetadataPrototype(IEnumerable<Attribute> attributes, Type containerType, Type modelType, string propertyName) 
{ 
    var metadata = base.CreateMetadataPrototype(attributes, containerType, modelType, propertyName); 

    if (metadata.IsReadOnly) 
    { 
     metadata.IsRequired = false; 
    } 

    return metadata; 
} 

protected override CachedDataAnnotationsModelMetadata CreateMetadataFromPrototype(CachedDataAnnotationsModelMetadata prototype, Func<object> modelAccessor) 
{ 
    var metadata = base.CreateMetadataFromPrototype(prototype, modelAccessor); 

    if (prototype.IsReadOnly) 
    { 
     metadata.IsRequired = false; 
    } 

    return metadata; 
} 

Sie werden auch

protected void Application_Start() 
{ 
    ModelMetadataProviders.Current = new RESModelMetadataProvider(); 
    ModelBinders.Binders.Add(typeof(SmartDate), new SmartDateModelBinder()); 

    ... 
} 
+0

Awesome, das sollte die akzeptierte Antwort sein: löst das Problem an der Quelle vollständig.Neuere Versionen von MVC haben unterschiedliche Methodennamen: 'GetMetadataForProperty'. VS kann die Stubs automatisch erstellen, wenn Sie' protected override' eingeben n füge einfach die if-Anweisungen hinzu. – David784

Verwandte Themen