2010-02-06 7 views
18

Edycja: Dodano Bounty dlatego szukam rozwiązania MVC3 (jeśli taki istnieje), inne niż to:Dlaczego środowisko ASP.NET MVC dba o moje właściwości tylko do odczytu podczas wiązania danych?

DataAnnotationsModelValidatorProvider.AddImplicitRequiredAttributeForValueTypes = false;


mam właściwość tylko do odczytu na moim „Adres” modelu 'CityStateZip'.

To wygodny sposób na uzyskanie miasta, stanu, zip z adresu w USA. Zgłasza wyjątek, jeśli kraj nie jest USA (dzwoniący powinien najpierw sprawdzić).

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

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

To jest część mojego modelu, więc jest związana. Przed ASP.NET MVC2 RC2 to pole nigdy nie powodowało problemu podczas wiązania danych. Nigdy nawet o tym nie myślałem - w końcu jest tylko do odczytu.

Teraz z wydaniem RC2 z stycznia 2010 r. Daje mi błąd podczas wiązania danych - ponieważ domyślny model spoiwa wydaje się chcieć sprawdzić tę wartość (nawet jeśli jest to tylko odczyt).

Jest to linia "base.OnModelUpdated", która powoduje wyzwolenie tego błędu.

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

Ostatnio minut zmienia się na modelbinder widocznie spowodowało tę zmianę w zachowaniu - ale nie jestem pewien, ale to, co z niego repurcussions są - lub czy nie jest to problem? Przekażę to zespołowi MVC, ale jestem ciekawy, czy ktokolwiek inny ma w międzyczasie jakieś sugestie, jak mogę zapobiec związaniu tej właściwości.

Ten artykuł jest wart przeczytania o zmianach - ale w ogóle nie wspomina o właściwościach readonly (nie, żebym się tego spodziewał). Kwestia (jeśli taka istnieje) może być szersza niż ta sytuacja - po prostu nie jestem pewna jakiejkolwiek repruzji - jeśli w ogóle!

Input Validation vs. Model Validation in ASP.NET MVC


Zgodnie z wnioskiem @haacked oto StackTrace:

uzyskać to poprzez dodanie następującej linii do każdego modelu i przygotowanie stanowiska do odpowiedniej metody działania. W tym przypadku dodałem go do mojego najprostszego możliwego modelu.

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

[TargetInvocationException: dostępowe Właściwość "Foo na cel 'Rolling_Razor_MVC.Models.ContactUsModel' wyrzucił następujące wyjątki: 'bar'] System.ComponentModel.ReflectPropertyDescriptor.GetValue (Component Object) + 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. < Sprawdź poprawność > d__5.MoveNext() +644 System.Web.Mvc.DefaultModelBinder.OnModelUpdated (ControllerContext controllerContext, ModelBindingContext BindingContext) +92 System.Web.Mvc.DefaultModelBinder.BindComplexElementalModel (ControllerContext controllerContext, ModelBindingContext BindingContext model obiektu) +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 (model TModel, przedrostek String , String [] includeProperties, String [] excludeProperties, IValueProvider valueProvider) +449 System.Web.Mvc.Controller.TryUpdateModel (model TModel) +73

+0

Co jest dokładny błąd, który widzisz? Byłoby również pomocne zobaczyć odpowiedni kontroler i kod widoku. –

+0

Potrzebujemy więcej szczegółów, ale domyślam się, że IsUsa jest fałszywa, gdy próbujemy odczytać tę właściwość, co powoduje, że wyjątek zostanie rzucony. Nie wiem, dlaczego czytaliśmy go podczas wiązania modelu, chyba że w formularzu, który jest wysyłany, znajduje się pole formularza o nazwie "CityStateZip". – Haacked

+0

@brad również dokładny błąd to "CityStateZip nie jest poprawny dla adresów międzynarodowych!" ;-) Aktualizuję pytanie za pomocą pełnego śledzenia stosu. duplikować, po prostu dodaj to do KAŻDEGO istniejącego modelu i zrób POST do odpowiedniego actionmethod: public string Foo {get {throw new Exception ("bar"); }} –

Odpowiedz

16

Uważam, że mam podobny problem. Mam pisał szczegóły:

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


edycji: odpowiedź od zespołu MVC (z powyższego URL):

Badaliśmy to i doszli do wniosku, że system walidacji zachowuje się jak spodziewany. Ponieważ sprawdzanie poprawności modelu polega na próbie uruchomienia sprawdzania poprawności we wszystkich właściwościach, a właściwości właściwości nie-nullable mają niejawny atrybut [Wymagany], sprawdzamy poprawność tej właściwości i wywołujemy jej proces gettera w procesie. Rozumiemy, że jest to przełomowa zmiana w stosunku do wersji V1 produktu, ale konieczne jest sprawne działanie nowego systemu weryfikacji modeli.

Masz kilka opcji do obejścia tego. Każdy z nich powinien działać:

  • Zmień właściwość Date na metodę zamiast właściwości; w ten sposób zostanie zignorowany przez ramy MVC.
  • Zmienić typ właściwości na DateTime? zamiast DateTime. Spowoduje to usunięcie niejawnej [Wymagane] z tej właściwości.
  • Wyczyść statyczną flagę DataAnnotationsModelValidatorProvider.AddImplicitRequiredAttributeForValueTypes. Spowoduje to usunięcie niejawnego [Wymagane] z wszystkich właściwości typu wartości Null bez możliwości zastosowania w całej aplikacji. Rozważamy dodanie do V3 produktu atrybutu, który będzie dla nas sygnałem "nie wiąż go, nie sprawdzaj go, po prostu udawaj, że ta właściwość nie istnieje".

Jeszcze raz dziękuję za zgłoszenie!

+0

Sprawdź odpowiedź na powyższy wpis. – Rudy

+1

Dwie rzeczy, o których nie wspomniałem, to fakt, że moja własność była tylko do odczytu, więc nie powinna nigdy być "potrzebna". więc to rozwiązanie nieco wkracza w mój projekt, ale rozwiązania wciąż działają.Drugą rzeczą jest to, że to i tak wybucha z wyjątkiem. to zdecydowanie nie jest dobre. jeśli model zawiedzie, model zawiedzie, ale wysadzenie w powietrze nie jest dobre –

+0

Mam dokładnie ten sam problem, przeczytaj mój post z linkiem, jeśli chcesz. czekam z niecierpliwością na mvc v3, ponieważ w v2 jest zbyt wiele nierozwiązanych/brakujących elementów, w tym ta i możliwość zwrócenia wielu widoków, aby zaktualizować różne fizyczne strony strony, lepszą obsługę niestandardowego sprawdzania poprawności serwera, itd. itd ... obejść te problemy w tej chwili, ale tylko dzięki użyciu "hack" i nie czuję elegancji kodowania, które powinienem czuć używając mvc; (- nie mogę czekać na v3. –

0

Oczywiście domyślam się, że mógłbym przekonwertować CityStateZip na GetCityStateZip(), ale nie mogę tego tak łatwo powiązać z czymś takim jak silverlight. To może działać dla tymczasowej poprawki dla każdego, kto doświadcza tego problemu.

0

MAM DOKŁADNIE TAKI SAMY PROBLEM !!

Aby uzyskać więcej informacji na temat mojego problemu, można odwiedzić ASP.NET MVC 2.0 Unused Model Property being called when posting a product to the server?

to oznacza musimy zaprogramować naszych nieruchomości przy założeniu, że zostaną one zwanego niespodziewanie (przed właściwości, które to zależy są tworzone/zainicjowany itd.) ... jeśli tak, oznacza to zmianę naszych praktyk programistycznych i chciałbym wiedzieć, jak postępować.

W międzyczasie, po prostu mam proste "jeśli" sprawdzić, który rozwiązuje problem.

+1

ogólnie właściwości mają być właśnie takie - głupie własności, jeśli masz zbyt dużo logiki biznesowej, to tak, będziesz musiał dokonać zmiany, ale być może powinieneś, a szkoda, że ​​nie mogliby dodać czegoś w rodzaju "nie zatwierdzaj", ale może to przyjdzie dla MVC3 –

2

Nadal mam ten sam problem z MVC3.

Myślę, że najlepszym sposobem jest po prostu do tego w global.asax (od odpowiedzi SevenCentral za):

DataAnnotationsModelValidatorProvider.AddImplicitRequiredAttributeForValueTypes = false; 

To spowoduje wyłączenie dla nich wszystkich

0

miałem podobny problem, a pole, którego nie spodziewałem się sprawdzić, otrzymywało błąd, gdy formularz odesłano do kontrolera. Po przeszukaniu go, natrafiłem na http://codeblog.shawson.co.uk/mvc-strongly-typed-view-returns-a-null-model-on-post-back/, gdzie wskazano, że konflikty nazw mogą powodować problemy.

Chociaż nie sądziłem, że moja klasa zmiennych post-back ma sprzeczne nazwy właściwości, zmiana nazwy obiektu otrzymującego błąd rozwiązała mój problem.

1

To wygląda na cały świat jak błąd. W pełni nie mogę zrozumieć, dlaczego ModelBinder musi sprawdzić moje właściwości tylko do odczytu (mogą to być pewne szczegóły techniczne, ale zdecydowanie nie rozumiem i nie chcę spędzać czasu próbując).

dodałem następujące Provider modelu metadane do mojego rozwiązania obejść problemu

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

Należy również dodać następujące do Global.asax.cs

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

    ... 
} 
+0

Awesome, to powinna być zaakceptowana odpowiedź: całkowicie rozwiązuje problem u źródła Nowsze wersje MVC mają różne nazwy metod: 'GetMetadataForProperty' .VS może automatycznie tworzyć kody pośredniczące, jeśli wpiszesz' protected override', n po prostu dodaj instrukcje if. – David784

Powiązane problemy