1

I have been stumped with this one. Users will randomly get a null reference exception when performing a postback. It seems to me the problem is coming from the model binder and possibly the order at which the properties a parsed. Just wanted to see if anyone has any input? Ive not been able to duplicate will debugging, only happens in production randomly on postback.

Fairly Simple ViewModel:

 public class ViewModel
{
    public Load Load { get; set; }

    public bool ReadOnly
    {
        get
        {
            return this.GetStatus(Load.Date);
        }
    }

    public Load PrevLoad { get; set; }

    private bool GetStatus(DateTime? date)
    {   
        if (date != null)
        {
            if (date.Value.DayOfWeek == DayOfWeek.Monday)
                date = date.Value.AddDays(-2);

            return ((DateTime.Now.AbsoluteEnd() - date.Value.AbsoluteEnd()).TotalHours) <= -24 ? false : true;
        }
        else
            return true;
    }
}

StackTrace (Note I x'd out business sensitive namespaces):

System.Reflection.TargetInvocationException: Property accessor 'ReadOnly' on object 

'XXX.XX.XXX.XXX.ViewModel' threw the following exception:'Object reference not set to an instance of an object.' ---> System.NullReferenceException: Object reference not set to an instance of an object.
   at XXX.XX.XXX.ViewModels.ViewModel.get_ReadOnly()
   --- End of inner exception stack trace ---
   at System.ComponentModel.ReflectPropertyDescriptor.GetValue(Object component)
   at System.Web.Mvc.DataAnnotationsModelValidator.<Validate>d__15.MoveNext()
   at System.Web.Mvc.ModelValidator.CompositeModelValidator.<Validate>d__1.MoveNext()
   at System.Web.Mvc.DefaultModelBinder.OnModelUpdated(ControllerContext controllerContext, ModelBindingContext bindingContext)
   at System.Web.Mvc.DefaultModelBinder.BindComplexModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
   at System.Web.Mvc.ControllerActionInvoker.GetParameterValue(ControllerContext controllerContext, ParameterDescriptor parameterDescriptor)
   at System.Web.Mvc.ControllerActionInvoker.GetParameterValues(ControllerContext controllerContext, ActionDescriptor actionDescriptor)
   at System.Web.Mvc.Async.AsyncControllerActionInvoker.<>c__DisplayClass1e.<BeginInvokeAction>b__16(AsyncCallback asyncCallback, Object asyncState)

When I pass null to this.GetStatus I get a different exception; So I know that cant be it.

Do you think this is throwing an exception because there technically isnt an instance of the ViewModel when modelBinding occurs and when attempting to access this.GetSatus it fails? That still wouldn't explain why this sometimes occurs.

Botonomous
  • 1,598
  • 1
  • 13
  • 37
  • According to the exception `Load` is `null`. Where does `Load` get populated? If the model binder doesn't receive enough information to construct the `Load` property then the default value for a reference type is `null`. The view model doesn't internally instantiate `Load` or check if it's `null`, so the exception is a very real possibility. – David Sep 18 '14 at 19:42
  • Where are you getting that out of the stack trace? Also, I Load shouldn't even be passed back to the controller because were not rendering hidden in the view for any properties in Load. ReadOnly is only used to make certain elements on the page disabled. Not needed on postback. – Botonomous Sep 18 '14 at 19:44
  • 1
    The first line of the stack trace: `ViewModel.get_ReadOnly()` That method only has one line: `return this.GetStatus(Load.Date);` Assuming that `this` can't be `null`, `Load` must be. It would appear that the framework's model validation is trying to read the properties in the view model, but that property throws an exception when anything tries to read it if `Load` is `null`. – David Sep 18 '14 at 19:47
  • possible duplicate of [What is a NullReferenceException and how do I fix it?](http://stackoverflow.com/questions/4660142/what-is-a-nullreferenceexception-and-how-do-i-fix-it) – mason Sep 18 '14 at 19:50
  • 1
    @mason I wouldn't think every general null reference exception would be a duplicate question. – Botonomous Sep 18 '14 at 19:51
  • @David Ok, is there anyway to prevent this besides adding a null check on Load? Im guessing there isnt. Also, if that's the cause, put this as an answer and ill acccept. – Botonomous Sep 18 '14 at 19:52
  • 2
    @Anon If you would read the link, you'll see that yes, every NRE is because of the same reason. And the fix is usually the same: initialize the object before using it. Or don't use it. – mason Sep 18 '14 at 19:53
  • 2
    @mason I know what a null reference exception. I am asking specifically about model binding and view model parsing. But thanks for pointing out the question. I will check it out. – Botonomous Sep 18 '14 at 19:55

1 Answers1

1

According to the first line of the stack trace:

at XXX.XX.XXX.ViewModels.ViewModel.get_ReadOnly()

The exception is coming from here:

public bool ReadOnly
{
    get
    {
        return this.GetStatus(Load.Date);
    }
}

Assuming that this can never be null, that just leaves Load. Looking at the rest of the view model, Load is never explicitly initialized. The view model assumes that Load will be set when the view model is created. If that's ever not the case, expect this exception.

Additionally in the stack trace, it looks like the framework is trying to read the properties on the view model in order to perform some validation. This particular view model makes the assumption that Load will be initialized before it will ever be read, which isn't a very safe assumption to make.

One approach could be to initialize Load in the view model:

public ViewModel()
{
    this.Load = new Load();
}

As long as the same assumption doesn't exist elsewhere in the stack, this will at least ensure that Load doesn't give you a NullReferenceException.

In general it should be the internal responsibility of any given model to construct itself in a valid state. Never assume that consuming code is going to set all of the properties.

David
  • 176,566
  • 33
  • 178
  • 245