35

Consider this simple controller:

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

Now, in my Create view, I want to check ViewBag object, to see if it has Error property or not. If it has the error property, I need to inject some JavaScript into the page, to show the error message to my user.

I created an extension method to check this:

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

Then, in the Create view, I wrote this line of code:

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

However, I get this error:

Cannot perform runtime binding on a null reference

Any idea?

Saeed Neamati
  • 35,341
  • 41
  • 136
  • 188

6 Answers6

100
@if (ViewBag.Error!=null)
{
    // Injecting JavaScript here
}
jazzcat
  • 4,351
  • 5
  • 36
  • 37
  • 4
    Dear @jazzcat, please first check your code, then send it. If I haven't set `ViewBag.Error` in my controller, which means that ViewBag won't have a property called `Error` at runtime, then I'll encounter an exception. – Saeed Neamati Jun 23 '12 at 09:28
  • 20
    @SaeedNeamati, jazzcat's code worked fine for me. For ViewBag, any item not found will be null. Remember that dynamic ultimately has some actual code behind it. ViewBag is a DynamicViewDataDictionary, which apparently decides to return null for non-existing "properties" rather than throwing an error. – devrelm Aug 27 '12 at 14:37
  • 4
    This should be the chosen answer! – Vishal Shah Jul 31 '13 at 10:36
  • 12
    Actually, you can improve this with a bit of other magic; @if(ViewBag.Error ?? false). This it will work if you set a boolean or not. – cirrus Nov 13 '13 at 16:57
  • 1
    MVC has a `DynamicViewDataDictionary` which the ViewBag inherits that implements this null-return behavior. Note that if you're using the Razor Engine outside of MVC, you'll get an exception if you try to access an undefined property rather than its returning `null`. See https://github.com/jlamfers/RazorMachine/issues/35 – Ryan Norbauer Mar 19 '14 at 19:53
22

Your code doesnt work because ViewBag is a dynamic object not a 'real' type.

the following code should work:

public static bool Has (this object obj, string propertyName) 
{
    var dynamic = obj as DynamicObject;
    if(dynamic == null) return false;
    return dynamic.GetDynamicMemberNames().Contains(propertyName);
}
Matthew Lock
  • 13,144
  • 12
  • 92
  • 130
JeffreyABecker
  • 2,724
  • 1
  • 25
  • 36
  • Good suggestion @JeffreyABecker. Thanks, but I get `Cannot perform runtime binding on a null reference` exception. – Saeed Neamati Sep 12 '12 at 11:09
  • 3
    Seems that I should use it like `((Object)ViewBag).Has("PropertyName")`. – Saeed Neamati Sep 12 '12 at 11:32
  • Resharper suggests "return dynamic != null && dynamic.GetDynamicMemberNames().Contains(propertyName);" instead of the last 2 lines. Nice solution! Thanks! – Dev.Jaap Sep 20 '13 at 13:28
4

Instead of using the ViewBag, use ViewData so you can check for the of the item you are storing. The ViewData object is used as Dictionary of objects that you can reference by key, it is not a dynamic as the ViewBag.

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

// Use the condition in the view
if(Convert.ToBoolean(ViewData["hideSearchForm"])
    hideSearchForm();
JustEngland
  • 1,371
  • 13
  • 30
  • How? Give us an example at least ;). – Saeed Neamati Jun 06 '12 at 04:33
  • 1
    Still ViewBag seems more elegant than ViewData. I don't like string indexes. – JustAMartin Oct 16 '12 at 10:20
  • 2
    The problem that was the dynamic viewbag does not allow you to check if the property exists, in which case the ViewData is the correct choice. However in mvc4 are some improvements to the view bag support. http://www.beletsky.net/2012/04/new-in-aspnet-mvc4-razor-changes.html – JustEngland Oct 16 '12 at 19:58
  • @Martin What meaningful difference is there between a string index and a dynamic member's name? ExpandoObject is just a dictionary under the covers, for instance. – Casey Jan 23 '15 at 15:42
  • @emodendroket - it's mostly just visual difference, the code looks a bit cleaner. – JustAMartin Jan 24 '15 at 21:05
3

You can use ViewData.ContainsKey("yourkey").

In controller:

ViewBag.IsExist = true;

In view:

if(ViewData.ContainsKey("IsExist")) {...}
Zachary Kniebel
  • 4,686
  • 3
  • 29
  • 53
3

I would avoid ViewBag here completely. See my thoughts here on this: http://completedevelopment.blogspot.com/2011/12/stop-using-viewbag-in-most-places.html

The alternative would be to throw a custom error and catch it. how do you know if the database is down, or if its a business logic save error? in the example above you just catch a single exception, generally there is a better way to catch each exception type, and then a general exception handler for the truly unhandled exceptions such as the built in custom error pages or using ELMAH.

So above, I would instead ModelState.AddModelError() You can then look at these errors (assuming you arent jsut going to use the built in validation) via How do I access the ModelState from within my View (aspx page)?

So please carefully consider displaying a message when you catch 'any' exception.

Community
  • 1
  • 1
Adam Tuliper
  • 29,982
  • 4
  • 53
  • 71
  • It looks like I'm "necrothreading" this :-) I've read your article, and I really use strong-typed models in MVC 4... But I don't have any qualms against using ViewBag for simple things. Most people coming from C#, and other strong-typed languages frown upon dynamics due to their heritage (I'm also a 'strong-typed' guy). But it all comes down to TESTING! If your views are tested the dynamic variables won't matter. In fact it's much better to use ViewBag everywhere and test it heavily than rely on strong-types to assure correctness. Good testing make the choice of dynamics vs strong-types moot. – Loudenvier Nov 03 '13 at 19:39
  • I love JavaScript, however I'm constantly bit by its loose typing. Dynamic variables matter. There's hidden behavior behind the scenes with viewbag in the helpers where any values take precedence to anything in a model. Secondly, they are brittle for refactoring and finding references and type assignments, etc. Testing isn't a catch all and testing is only how good your tests are. No one's tests are 100%, not at any place or project I've ever seen and that's many. Its a best effort and you can surely introduce bugs that aren't caught by tests, to which you update your tests to handle – Adam Tuliper Nov 03 '13 at 21:56
  • this new fix, but that still doesn't prevent it. While I'm happy you posted a response, I cant agree with this: "In fact it's much better to use ViewBag everywhere and test it heavily than rely on strong-types to assure correctness" Ask any architect whose been using MVC on many projects if they agree with that statement. ViewModels is the preferred method for a whole list of reasons. Why would it be better to use ViewBag and test heavily, rather than use a property in a viewmodel, and simply not have to worry about it? – Adam Tuliper Nov 03 '13 at 21:57
  • Adam, I think it is a lot overstated the contribution of strong-typing towards correctness. Unit testing (and TDD) is really the main evolution/contribution towards it in ages. While I'm more comfortable inside a strongly-typed environment, I came to "accept" that the dynamic guys really changed my assumptions that strong-typing equals less bugs/more robustness. They had no "language" help, so they had to rely solely on unit testing. That's why the serious Javascript projects have so few bugs (jQuery, node.js, CoffeeScript). And that's why I don't mind passing a Title on the ViewBag :-) – Loudenvier Nov 03 '13 at 22:22
  • 'Serious' javascript projects also have bugs. jQuery has had thousands in its lifetime. Testing hasn't stopped the bugs. If you are using VieWModels, by definition the pattern should contain information for the view, otherwise you are losing a well established benefit of using them, I can't argue that point. Many architects have figured that out, thats why viewmodels is the best practice approach. It doesnt mean yours wont work, but you do open up for 1. inconsistency in using viewmodels, and #2. all the prior mentioned stuff. – Adam Tuliper Nov 09 '13 at 23:04
  • Sure, as devs we can decide how we want, but established arch. best practices are there usually for a reason. Again, not pointing and saying 'you are wrong' as there are many approaches, but consider those that have gone before you and why the practices exist – Adam Tuliper Nov 09 '13 at 23:04
  • Adam, here is not the place for this discussion (mea culpa!), but don't believe for a single nanosecond I don't agree with you, and I'm a LOT more comfortable working with View Models... My point is just that strong-typing is not what really helps most to ensure correctness. Many people advocate it as a means towards that goal. I don't agree with it. It has a LOT of benefits, mostly because the tools in VS work well with strong-types but not with dynamic ones (take refactoring for example), so, in "our" environment, strong-typing is the way to go! (unless it is just a view Title :-) – Loudenvier Nov 10 '13 at 16:17
0

I need to test this but:

@if (ViewBag.ABoolParam ?? false)
{
    //do stuff
}

I think will give you either the value of the ViewBag property, or return a default value if missing.

Brady Moritz
  • 8,624
  • 8
  • 66
  • 100