5

Consider this ASP.NET MVC 5 controller:

public class MyController : Controller {
    public ActionResult Index(int? id) {
        ViewBag.MyInt = id;
        return View();
    }
}

And this view:

<p>MyInt.HasValue: @MyInt.HasValue</p>

When I invoke the URL /my/ (with a null id), I get the following exception:

An exception of type 'Microsoft.CSharp.RuntimeBinder.RuntimeBinderException' occurred in System.Core.dll but was not handled in user code

Additional information: Cannot perform runtime binding on a null reference

Conversely, if I pass an ID in (eg, /my/1):

An exception of type 'Microsoft.CSharp.RuntimeBinder.RuntimeBinderException' occurred in System.Core.dll but was not handled in user code

Additional information: 'int' does not contain a definition for 'HasValue'

This suggests to me that ViewBag.MyInt is not of type Nullable<int>, but of either int or null.

Is this the ViewBag doing this? Or, is it something more fundamental about boxing Nullable types like this? Or, something else?

Is there another way to do this?

(I suppose that I could just change my check to ViewBag.MyInt == null, but let's pretend I really needed a Nullable type for some reason)

tereško
  • 58,060
  • 25
  • 98
  • 150
Mike Caron
  • 14,351
  • 4
  • 49
  • 77
  • I like @BenjaminPaul's answer better, but you could always use ViewData instead. You would have to cast it as int? in the view, but it wouldn't give you errors. – bsayegh Mar 31 '14 at 15:19

3 Answers3

3

I would suggest that you create a view model which will give you full flexibility to make "MyInt" a null-able type for this.

Of course, the alternative would be to only set "MyInt" if it is not null...

public class MyController : Controller {
    public ActionResult Index(int? id) {
        if (id.HasValue)
        {
            ViewBag.MyInt = id;
        }
        return View();
    }
}

View:

@if (ViewBag.MyInt != null)
{
    <p>Has an Id</p>
}
else
{
    <p>Has no Id.</p>
}

Personally, I would go with a viewmodel as it's best practice, I rarely use ViewBag unless its for a VERY simple scenario.

BenjaminPaul
  • 2,931
  • 19
  • 18
  • "Create a view model" is undoubtedly the best answer, so I'll accept for that. However, I'm not sure what your snippet is meant to accomplish? That does the same thing as my code, except it's more verbose. – Mike Caron Mar 31 '14 at 15:46
0

I'm not sure the reason, but you can always cast it as a nullable in the view.

<p>MyInt.HasValue: @(((int?)MyInt).HasValue)</p>

Although, that may seem like overkill.

Smeegs
  • 9,151
  • 5
  • 42
  • 78
0

ViewBag is an DynamicViewDataDictionary object (see answer by Robert Harvey and ASP.NET source code).

Nullable is a value type and gets boxed when you add it to ViewBag. See this article, and especially remarks, on MSDN. According to the same article, "when a nullable type is boxed, the CLR automatically boxes the underlying value of the Nullable object"...

It is safe to test a ViewBag property for null. If it is not null, the actual value is that of the underlying type of the original Nullable object. Therefore this code works:

@if (ViewBag.MyInt != null)
{
    <p>@ViewBag.MyInt</p>
}

and even this:

<p>@ViewBag.MyInt</p>

If MyInt is not set in the ViewBag, the null value is rendered as blank. If it is set by assigning a Nullable value, then the actual value is an int.

Community
  • 1
  • 1
Mark Meyerovich
  • 193
  • 3
  • 9