2011-07-26 17 views
5

Czy mogę zrobić coś takiego?Utworzono nowy CustomModelBinder z tego, który już działał. Dlaczego nowy nigdy nie zostaje wezwany do zrobienia żadnego wiązania?

[HttpPost] 
public ActionResult Index(WizardViewModel wizard, IStepViewModel step) 
{ 

Gdzie mam następujących w moim Global.asax.cs Application_Start

ModelBinders.Binders.Add(typeof(IStepViewModel), new StepViewModelBinder()); 
    ModelBinders.Binders.Add(typeof(WizardViewModel), new WizardViewModelBinder()); 

Aktualizacja

Więc starałem się zobaczyć co jest nie tak. Oto mój nowy kod. Wygląda na to, że problem polega na tym WizardViewModel i jego segregatorze. Co "mówi" aplikacji o oczekiwaniu i nadchodzącym modelu Kreatora?

[HttpPost] 
public ActionResult Index(WizardViewModel wizard) 
{ 

Gdzie mam następujących w moim Global.asax.cs Application_Start

ModelBinders.Binders.Add(typeof(WizardViewModel), new WizardViewModelBinder()); 

Pełny kod Binder

namespace Tangible.Binders 
{ 
    public class StepViewModelBinder : DefaultModelBinder 
    { 
     protected override object CreateModel(ControllerContext controllerContext, ModelBindingContext bindingContext, Type modelType) 
     { 
      var stepTypeValue = bindingContext.ValueProvider.GetValue("StepType"); 
      var stepType = Type.GetType((string)stepTypeValue.ConvertTo(typeof(string)), true); 
      var step = Activator.CreateInstance(stepType); 

      bindingContext.ModelMetadata = ModelMetadataProviders.Current.GetMetadataForType(() => step, stepType); 
      return step; 
     } 
    } 

    public class WizardViewModelBinder : DefaultModelBinder 
    { 
     protected override object CreateModel(ControllerContext controllerContext, ModelBindingContext bindingContext, Type modelType) 
     { 
       var wizardValue = bindingContext.ValueProvider.GetValue("wizard"); 
       if (wizardValue != null) 
       { 
        var wizardType = Type.GetType((string)wizardValue.ConvertTo(typeof(string)), true); 
        var wizard = Activator.CreateInstance(wizardType); 

        bindingContext.ModelMetadata = ModelMetadataProviders.Current.GetMetadataForType(() => wizard, wizardType); 
        return wizard; 
       } 
       else 
       { 
        var wizard = new Tangible.Models.WizardViewModel(); 
        wizard.Initialize(); 
        return wizard; 
       } 
     } 
    } 
} 
+0

Czy to próbował? –

+0

Tak, ale mogłem bardzo łatwo mieć wiele innych problemów, które powodują, że to nie działa. Zanim przejdę dalej, pomyślałem, że powinienem sprawdzić, czy to możliwe. –

+0

Doug, jak pamiętam z twojego poprzedniego pytania na http://stackoverflow.com/questions/6834814/modelmetadata-custom-class-attributes-and-an-indescribable-question, WizardViewModel zawarł 'IList ' jako atrybut . Czy tak jest nadal?Jeśli tak, to twój WizardViewModelBinder powinien prawdopodobnie obsłużyć także powiązanie dla potomnej klasy IStepViewModel. Jak sugerowali inni, opublikuj swój model kodu spoiwa. – counsellorben

Odpowiedz

3

Odpowiedź jest prosta - tak! To właśnie powinieneś zrobić, gdy masz niestandardową logikę do wiązania wartości z parametrami. Możesz to zrobić nawet za pomocą ModelBinderAttribute, ustawionego indywidualnie dla każdego z parametrów.

[HttpPost] 
    public ActionResult Index([ModelBinder(typeof(WizardViewModelBinder))]WizardViewModel wizard, 
[ModelBinder(typeof(StepViewModelBinder))]IStepViewModel step) 
    { } 

I jak widzę, błąd jest w kodzie modelu segregatora. Nie mam czasu, aby to sprawdzić, ale o ile pamiętam, CreateModel jest używany przez moduł wiążący do tworzenia instancji modelu, a następnie ta zwracana instancja jest powiązana z modelem. Zastąp więc BindModel zamiast CreateModel i wpisz logikę powiązania modelu w BindModel. To na pewno działa.

public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext) 
{ 
//your model binding logic here 
} 
+0

Teraz jest to ekstra smaczna, chrupiąca odpowiedź. Przyjmę to, gdy tylko będę miał okazję go przetestować. Jeśli uznałeś to pytanie za interesujące, byłbym wdzięczny za podniesione pytanie: –

+0

Niestety, nie przyniosło to żadnych zmian. Mój CustomModelBinder dla WizardViewModel nadal nie jest wywoływany. –

+0

Oba sposoby - za pośrednictwem Global.asax i za pośrednictwem atrybutów parametrów powinny działać. Opublikuj swój kod ModelBinder, być może to może nam pomóc – archil

0

Zrobiłem coś podobnego w przeszłości, gdzie zdałem ciąg a następnie podzielić wartość.

+0

Moje zrozumienie to cały cel funkcji ModelBinders, aby umożliwić przekazywanie złożonych obiektów do działań kontrolerów jako parametrów, zamiast prostych typów danych. Czy to jest nieprawidłowe? –

+0

ModelBinders zostały wprowadzone w wersji 3.5. Wcześniej moje rozwiązanie było skuteczną, ale prymitywną opcją. –

0

Powiedziałbym, że odpowiedź brzmi: tak! W swoim komentarzu obawiasz się "wielu innych problemów", które mogą powodować problemy. Nie wiedząc, jakie masz problemy, trudno ci pomóc. Ale to, co zrobiliście, to dokładnie to, do czego są przeznaczone segregatory do modeli. I nie ma powodu, dlaczego powinieneś mieć tylko jeden obiekt na działanie.

+0

Miałem na myśli, że jest możliwe, mój kod w innym miejscu powoduje nieoczekiwane wyniki. Wolałbym zobaczyć przykład z prawdziwego świata. Zamiast entuzjastycznego tak. To sytuacja, w której nie chciałem walczyć z kodem, którego ledwie rozumiem, bez wkładu niektórych ekspertów. –

+0

Naprawdę nie widzę twojego problemu: używasz segregatorów modeli dokładnie w taki sposób, w jakim zostały zaprojektowane. Moim zdaniem używanie atrybutów zaproponowanych przez archil jest zwykle złym wyborem, ale zależy to od konkretnego przypadku użycia. Jeśli utworzysz dziwne hierarchie typów, możesz również uzyskać problemy. Ale to wszystko jest niezależne od modeli segregatorów i (mniej lub bardziej) zupełnie innego tematu. Tak więc moja odpowiedź brzmi: Tak, używasz segregatorów modelowych we właściwy sposób! – Achim

+0

Nie jestem pewien, czy muszę powtórzyć moje pytanie, ale naprawdę potrzebuję przykładu wielu segregatorów w akcji. Tak zapewnił Archil. –

0

Byłem bardzo rozczarowany, że obręcze ASP.NET MVC model wiążący konieczny mnie przeskoczyć, aby uzyskać pewne podstawowe deserializacji.

Ponieważ modelowanie nie było tak bliskie przezroczystości, jak się spodziewałem w przypadku złożonych modeli/ViewModels, po prostu zbudowałem niestandardowy ActionFilter, aby rozwiązać typy [i TYLKO typy] Chcę deserializować w metodzie akcji i użyć ServiceStack.Text dla wszystkie moje potrzeby związane z serializacją/deserializacją.

Spójrz tutaj:

https://gist.github.com/3b18a58922fdd8d5a963