Sunday, November 11, 2012

MVC and Passing Null Models to Partial Views

This is something that I've wanted to post ever since I discovered it last Spring.

What do you think happens when you have a partial view that takes a model (let's say our view is for a Customer entity, and our partial view is for some child property of a Customer, such as Shipping Address) and you need to pass a null to it?

Well, whatever you expect, you probably will be surprised at what actually happens: the framework will pass the model of the parent view to the partial view instead of your Null.

A little digging with Reflector, and it's clear why:
internal virtual void RenderPartialInternal(string partialViewName, ViewDataDictionary viewData, object model, TextWriter writer, ViewEngineCollection viewEngineCollection)
{
    if (string.IsNullOrEmpty(partialViewName))
    {
        throw new ArgumentException(MvcResources.Common_NullOrEmpty, "partialViewName");
    }
    ViewDataDictionary dictionary = null;
    if (model == null)
    {
        if (viewData == null)
        {
            dictionary = new ViewDataDictionary(this.ViewData);
        }
        else
        {
            dictionary = new ViewDataDictionary(viewData);
        }
    }
    else if (viewData == null)
    {
        dictionary = new ViewDataDictionary(model);
    }
    else
    {
        dictionary = new ViewDataDictionary(viewData) {
            Model = model
        };
    }
    ViewContext viewContext = new ViewContext(this.ViewContext, this.ViewContext.View, dictionary, this.ViewContext.TempData, writer);
    FindPartialView(viewContext, partialViewName, viewEngineCollection).Render(viewContext, writer);
}

 

If the model is null, the variable dictionary will be assigned a new ViewDataDictionary containing either the viewData with which the partial view was invoked, or the parent view’s own ViewData.  Thus the partial view will be passed data belonging, not to itself, but to the parent. 

But sometimes you want to pass a null!  Sometimes a null is semantically meaningful!  Too bad:  when your partial view attempts to access its model, even to compare it to Null, it will find that something else has been passed in its place.