Question

I have a view and a partial view. Within the controller action methods, I have a using statement which establishes some back-end threading context, including providing access to a model object for display in the view.

The problem that I'm having is that while the context and the associated model object are available for the main view, they are disposed before the partial view is rendered. This seems to be the case regardless of whether I pass the model object from the view to the partial view, or reference it some other way.

The controller view action method:

public ActionResult Index()
{
  using (var context = GetContext()) {
    return View(Context.MyModelObject);
  }
}

The controller partial view action method:

[ChildActionOnly]
public ActionResult MyPartialView(ModelObject modelObject)
{
  return PartialView(modelObject);
}

The view:

@model ModelObject

@Model.Name

@{Html.RenderAction("MyPartialView", "MyController", new {modelObject = @Model});}

The partial view:

@model ModelObject

@foreach(var item in Model.Items) {
  <div>@item.Name</div>
}

If I comment out the RenderAction line of the view, the view displays just fine, accessing the property of the model because the context has not yet been disposed at the end of the using.

However, if I leave it in with the intent of the partial view being rendered, the context has been disposed of, leaving my model object no longer accessible. I would think the using in the main view controller method would not be finished until the view and all its partial views are rendered, but that doesn't seem to be the case. Are partial views deferred to be rendered at some other time? Is there a way around this?

Right now I have a solution which will involve writing a lot of extra code: making a "view model" object which has only the bits of the model object that I need for display in this specific view while it hasn't yet been disposed, then having the view and partial views use that. However, this will be very undesirable as it will result in a lot of duplication between the model and the view models, which will be a subset. It would be very convenient to use the model directly in the view.

The other possibility is that we could alter our backend to dispose of things differently such that they are still available for the partial view whenever it gets around to rendering, but this also seems like a hack.

In summary, is there a better way to do this in the view/controller? Am I making some erroneous assumptions?

Was it helpful?

Solution

MVC was designed with Unit testability in mind. As such, it doesn't render the view when you call View(), it just creates a structure which gets rendered after it returns from the controller.

This design makes it easier to unit test controllers because it doesn't actually require an active web server connection to execute the controller logic.

But, this also means that since you have a using statement in your controller, the view is not actually rendered until after you have returned from the function, and thus the using has called delete on the data context. Thus, your queries will not execute.

You get around this by executing the query within the controller, such as calling .ToList() on the object. You still have to be careful not to execute any lazy operations after returning.

However, a better approach is to not pass your data objects directly to the view, but instead use a view model which you populate from the returned data objects.

OTHER TIPS

Try this

@Html.Partial("MyPartialView", Model)
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top