2011-12-27 9 views
33

Rozważmy prosty kontroler:sprawdzając, czy ViewBag ma właściwość lub nie, warunkowo wstrzyknąć JavaScript

Porduct product = new Product(){ 
    // Creating a product object; 
}; 
try 
{ 
    productManager.SaveProduct(product); 
    return RedirectToAction("List"); 
} 
catch (Exception ex) 
{ 
    ViewBag.ErrorMessage = ex.Message; 
    return View("Create", product); 
} 

Teraz, moim Create widzenia, chcę sprawdzić ViewBag obiektu, aby zobaczyć, czy to ma Error własność lub nie. Jeśli ma właściwość błędu, muszę wstrzyknąć trochę kodu JavaScript na stronę, aby wyświetlić komunikat o błędzie dla mojego użytkownika.

I stworzył metodę rozszerzenia aby to sprawdzić:

public static bool Has (this object obj, string propertyName) 
{ 
    Type type = obj.GetType(); 
    return type.GetProperty(propertyName) != null; 
} 

Następnie w widoku Create pisałem ten wiersz kodu:

@if (ViewBag.Has("Error")) 
{ 
    // Injecting JavaScript here 
} 

Jednak uzyskać ten błąd:

Cannot perform runtime binding on a null reference

Każdy pomysł?

+0

'ViewBag' jest zerowy? –

+0

Który kod faktycznie generuje ten błąd? –

+0

@JohnSaunders, jak widzisz ustawiłem 'ViewBag.Error' w moim kontrolerze? Jak może być pusty? –

Odpowiedz

20

Twój kod nie robi praca bo ViewBag to nie dynamic object a 'prawdziwy' typ.

następujący kod powinien działać:

public static bool Has (this object obj, string propertyName) 
{ 
    var dynamic = obj as DynamicObject; 
    if(dynamic == null) return false; 
    return dynamic.GetDynamicMemberNames().Contains(propertyName); 
} 
+0

Dobra sugestia @JeffreyABecker. Dzięki, ale otrzymuję komunikat "Nie można wykonać wiązania wykonawczego dla wyjątku zerowego odniesienia". –

+3

Wygląda na to, że powinienem użyć go jak '((Object) ViewBag) .Has (" PropertyName ")'. –

+0

Resharper sugeruje "return dynamic! = Null && dynamic.GetDynamicMemberNames(). Zawiera (propertyName);" zamiast dwóch ostatnich linii. Ładne rozwiązanie! Dzięki! –

3

Unikałbym tutaj całkowicie ViewBag. Zapoznaj się z moimi przemyśleniami na ten temat: http://completedevelopment.blogspot.com/2011/12/stop-using-viewbag-in-most-places.html

Alternatywą byłoby rzucenie błędu niestandardowego i uchwycenie go. skąd wiesz, czy baza danych nie działa, czy też logika biznesowa zapisuje błąd? w powyższym przykładzie po prostu wychwycisz jeden wyjątek, zazwyczaj istnieje lepszy sposób na wychwycenie każdego typu wyjątku, a następnie ogólny wyjątek dla naprawdę nieobsługiwanych wyjątków, takich jak wbudowane niestandardowe strony błędów lub użycie ELMAH.

Więc powyżej, chciałbym zamiast ModelState.AddModelError() Następnie można spojrzeć na tych błędów (zakładając, że nie jest z ciebie jsut zamiar użyć wbudowanego w walidacji) poprzez How do I access the ModelState from within my View (aspx page)?

Więc proszę dokładnie rozważyć, wyświetlając wiadomość po złapaniu "jakiegokolwiek" wyjątku.

+0

Wygląda na to, że jestem "nieczytelny" to :-) Przeczytałem twój artykuł i naprawdę używam modeli z silnymi typami w MVC 4 ... Ale nie mam żadnych zastrzeżeń co do używania ViewBag do prostych rzeczy. Większość ludzi wywodzących się z języka C# i innych języków o silnym typie jest marszczonych na dynamikę ze względu na swoje dziedzictwo (jestem też facetem o silnym typie). Ale wszystko sprowadza się do TESTOWANIA! Jeśli Twoje poglądy zostaną przetestowane, zmienne dynamiczne nie będą miały znaczenia. W rzeczywistości znacznie lepiej jest korzystać z ViewBag wszędzie i testować go silniej niż polegać na silnych typach, aby zapewnić poprawność. Dobre testy sprawiają, że wybór dynamiki w porównaniu z silnymi typami moot. – Loudenvier

+0

Uwielbiam JavaScript, ale wciąż jestem trochę po luźnym pisaniu. Zmienne dynamiczne mają znaczenie. Za kulisami kryje się ukryte zachowanie z viewbackiem w helperach, gdzie wszelkie wartości mają pierwszeństwo przed wszystkim w modelu. Po drugie, są kruche do refaktoryzacji i odnajdywania referencji i przypisań typów, itp. Testowanie nie jest haczykiem, a testowanie to tylko to, jak dobre są twoje testy. Żadne testy nie są w 100%, ani w żadnym miejscu ani projekcie, jaki kiedykolwiek widziałem, a to wiele. Jest to najlepszy wysiłek i na pewno możesz wprowadzić błędy, które nie zostały przechwycone przez testy, do których zaktualizujesz swoje testy, aby obsłużyć tę nową poprawkę –

+0

, ale to jeszcze nie uniemożliwia. Chociaż jestem szczęśliwy, że napisałeś odpowiedź, nie mogę się z tym zgodzić: "W rzeczywistości znacznie lepiej jest używać ViewBag wszędzie i testować go silniej niż polegać na silnych typach, aby zapewnić poprawność" Zapytaj dowolnego architekta, który korzystał z MVC w wielu projektach jeśli zgadzają się z tym stwierdzeniem. ViewModels jest preferowaną metodą z całej listy powodów. Dlaczego lepiej byłoby korzystać z ViewBag i testować je intensywniej, zamiast korzystać z właściwości w viewmodelu i po prostu nie musieć się o to martwić? –

4

Zamiast korzystać z ViewBag, należy użyć ViewData, aby można było sprawdzić, czy przedmiot jest przechowywany. Obiekt ViewData jest używany jako słownik obiektów, do których można odwoływać się za pomocą klucza, nie jest dynamiczny jak ViewBag.

// Set the [ViewData][1] in the controller 
ViewData["hideSearchForm"] = true;  

// Use the condition in the view 
if(Convert.ToBoolean(ViewData["hideSearchForm"]) 
    hideSearchForm(); 
+0

Jak? Daj nam przykład przynajmniej;). –

+0

Oto mała próbka. – JustEngland

+1

Nadal ViewBag wydaje się bardziej elegancki niż ViewData. Nie lubię indeksów ciągów. – JustAMartin

98
@if (ViewBag.Error!=null) 
{ 
    // Injecting JavaScript here 
} 
+4

Drogi @ jazzcat, proszę najpierw sprawdzić kod, a następnie wysłać go.Jeśli nie ustawiłem 'ViewBag.Error' w moim kontroler, co oznacza, że ​​ViewBag nie będzie mieć właściwość o nazwie" Błąd "w czasie wykonywania, wtedy napotkam wyjątek. –

+20

@SaeedNeamati, kod jazzcat's działał dobrze dla mnie. W przypadku elementu ViewBag dowolny element nie znaleziony będzie mieć wartość NULL. Pamiętaj, że dynamizm ma za sobą jakiś rzeczywisty kod. ViewBag to DynamicViewDataDictionary, który najwyraźniej decyduje się zwrócić wartość null dla nieistniejących "właściwości", zamiast zgłaszać błąd. – devrelm

+1

Yup, devrelm ma rację, działa też dla mnie ... – user1068352

2

Można użyć ViewData.ContainsKey("yourkey").

W sterowniku:

ViewBag.IsExist = true; 

Biorąc:

if(ViewData.ContainsKey("IsExist")) {...} 
+0

użyj znaczników kodu, jeśli to konieczne. – matiasg