2011-12-27 3 views
33

Рассмотрим простой контроллер:Проверка, если ViewBag имеет свойство или нет, условно инъекционные 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); 
} 

Сейчас, на мой Create зрения, я хочу, чтобы проверить ViewBag объект, чтобы увидеть, если он имеет Error собственности или нет. Если у него есть свойство error, мне нужно добавить некоторый JavaScript на страницу, чтобы показать сообщение об ошибке моему пользователю.

Я создал метод расширения, чтобы проверить это:

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

Затем, в Create зрения, я написал эту строку кода:

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

Однако, я получаю эту ошибку:

Cannot perform runtime binding on a null reference

Есть идеи?

+0

'ViewBag' является недействительным? –

+0

Какой код действительно генерирует эту ошибку? –

+0

@JohnSaunders, как вы видите, я установил 'ViewBag.Error' в моем контроллере? Как это может быть null? –

ответ

20

Ваш код не работает, потому что ViewBag является dynamic object не 'реальный' тип.

следующий код должен работать:

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

Хорошее предложение @JeffreyABecker. Спасибо, но я получаю исключение «Невозможно выполнить привязку времени выполнения при исключении нулевой ссылки». –

+3

Кажется, что я должен использовать его как '((Object) ViewBag) .Has (" PropertyName ")'. –

+0

Resharper предлагает «return dynamic! = Null && dynamic.GetDynamicMemberNames(). Содержит (propertyName);" вместо двух последних строк. Хорошее решение! Благодаря! –

3

Я бы полностью избежал ViewBag здесь. См. Мои мысли здесь: http://completedevelopment.blogspot.com/2011/12/stop-using-viewbag-in-most-places.html

Альтернативой было бы выбросить пользовательскую ошибку и поймать ее. откуда вы знаете, если база данных не работает, или если ошибка бизнес-логики сохраняет ошибку? в приведенном выше примере вы просто поймаете единственное исключение, как правило, есть лучший способ поймать каждый тип исключения, а затем общий обработчик исключений для действительно необработанных исключений, таких как встроенные страницы пользовательских ошибок или использование ELMAH.

Так выше, я бы вместо ModelState.AddModelError() Вы можете посмотреть на этих ошибках (если вы Арент этого нужно просто собираетесь использовать встроенные проверки) через How do I access the ModelState from within my View (aspx page)?

Поэтому, пожалуйста, внимательно рассмотреть отображающим когда вы поймаете «любое» исключение.

+0

Похоже, что я «некропрочитаю» это :-) Я прочитал вашу статью, и я действительно использую модели с сильным типом в MVC 4 ... Но у меня нет никаких проблем с использованием ViewBag для простых вещей. Большинство людей, пришедших с C#, и другие языки с сильным типом, не понимают динамики из-за своего наследия (я тоже «сильный»). Но все сводится к ТЕСТИРОВАНИЮ! Если ваши взгляды проверены, динамические переменные не будут иметь значения. На самом деле гораздо лучше использовать ViewBag повсюду и тестировать его в большей степени, чем полагаться на сильные типы, чтобы обеспечить правильность. Хорошее тестирование делает выбор динамики против сильных типов спорным. – Loudenvier

+0

Я обожаю JavaScript, но я постоянно разбираюсь в его бесшумной печати. Важны динамические переменные. Там скрытое поведение за кулисами с viewbag в помощниках, где любые значения имеют преимущество перед чем-либо в модели. Во-вторых, они хрупки для рефакторинга и поиска ссылок и назначений типов и т. Д. Тестирование не является уловкой, и тестирование - это только то, насколько хороши ваши тесты. Никакие тесты не являются 100%, ни в каком месте или проекте, который я когда-либо видел, и это много. Это лучшее усилие, и вы можете наверняка ввести ошибки, которые не попадают на тесты, на которые вы обновляете свои тесты, чтобы обрабатывать –

+0

это новое исправление, но это все еще не мешает. Хотя я счастлив, что вы опубликовали ответ, я не могу согласиться с этим: «На самом деле гораздо лучше использовать ViewBag повсюду и тестировать его в большей степени, чем полагаться на сильные типы, чтобы гарантировать правильность». Спросите любого архитектора, который использовал MVC для многих проектов если они согласны с этим заявлением. ViewModels - предпочтительный метод для целого списка причин. Почему лучше было бы использовать ViewBag и тестировать, а не использовать свойство в режиме просмотра, и просто не нужно беспокоиться об этом? –

4

Вместо использования ViewBag используйте ViewData, чтобы вы могли проверить предмет, который вы храните. Объект ViewData используется в качестве словаря объектов, к которым вы можете ссылаться по ключу, он не является динамическим, как ViewBag.

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

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

Как? Дайте нам пример хотя бы;). –

+0

Вот небольшой пример – JustEngland

+1

Still ViewBag кажется более элегантным, чем ViewData. Мне не нравятся строковые индексы. – JustAMartin

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

Уважаемый @jazzcat, пожалуйста, сначала проверьте свой код, а затем отправьте его.Если я не установил 'ViewBag.Error' в моем контроллере, это означает, что ViewBag не будет иметь свойство« Ошибка »во время выполнения, тогда я столкнусь с исключением. –

+20

@SaeedNeamati, код jazzcat отлично работал для меня. Для ViewBag любой элемент, который не найден, будет null. Помните, что динамика в конечном итоге имеет некоторый фактический код. ViewBag - это DynamicViewDataDictionary, который, по-видимому, решает вернуть null для несуществующих «свойств», а не бросать ошибку. – devrelm

+1

Yup, devrelm is right, работает и для меня тоже ... – user1068352

2

Вы можете использовать ViewData.ContainsKey("yourkey").

В контроллере:

ViewBag.IsExist = true; 

В свете:

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

, пожалуйста, используйте теги кода, если это необходимо. – matiasg