Subscribe to Windows IT Pro
October 20, 2011 12:00 PM

Populating an ASP.NET MVC View with Globally Shared Data

Use an action filter to fill up view models with data shared across multiple views
Dev Pro
InstantDoc ID #140269
Rating: (0)

About a year ago, I wrote an article for DevProConnections exploring ways to inject global data into ASP.NET MVC views (see "Dealing with Data Shared Among Views"  The solutions that I presented are, for the most part, common tricks. Recently, however, I needed to enhance those solutions to better address a problem in a larger application that had several master/detail views.

This problem isn’t unique to master/detail views but shows up clearly when you deal with them. When you write a master/detail view in Web Forms, you have only one concern: how to get key information for the item that is selected in the master. When you know how to do that, you can populate the detail view and render the page; you don't need to worry about refilling the master view. That's one benefit of the viewstate.

In ASP.NET MVC, you have no viewstate. In this context, the news isn’t great because it means that you need to be concerned with filling the detail view and refilling the master view. The issue isn’t really a coding problem; it's purely a design issue. But unresolved design issues never die—they come back unexpectedly as the size of the project grows.

The Design Issue

In ASP.NET MVC, each request results a controller conducting an action or, better yet, triggering a service component. The action relates to a specific user request, such as "show me the list of countries where the company has subsidiaries" or "show me details about this country." Ideally, you want to serve the former request by running code that gets only the list of countries, and serve the latter request by running code that gets only details about a given country. The issue is that ASP.NET MVC forces the code that serves the second request to also provide the list of countries (again). Otherwise, the drop-down list of countries will be empty when the detail view is shown (see Figure 1).

Figure 1: Improperly filled master view
Figure 1: Improperly filled master view

Figure 2 shows a sample controller class for the application that Figure 1 shows. The controller uses injected worker components to serve actions and get view model objects. (This approach is an emerging pattern for ASP.NET MVC applications, and I recommend it to everybody, but not for just any application. The approach is described thoroughly in Programming ASP.NET MVC 3, Microsoft Press, 2011.)

The worker service class does the job of populating view model objects, which the controller then hands to the view engine. Figure 3 shows a sample worker service. The first method in the listing returns a fully initialized view model object, which has the page title and a list of countries. The second method returns a view model object that sets the title and country details, but does not list countries.

Admittedly, you could just add an extra call to GetCountryViewModel to retrieve and store the list of countries. You wouldn’t experience the failure that is shown in Figure 1 and could leave the office early. But what if the amount of information that the multiple views share is large and comes from scattered sources? You would need that information in a variety of controllers (or worker services) for a variety of views. How many dependencies should you be passing around?

The idea is to leave the controller (or worker service) in charge of only the data that must be manipulated in that specific call context, and to move the remaining code elsewhere. An excellent place to move this extra code is to an action filter.

The ViewModelFiller Action Filter

Action filters are small chunks of behavior that you can attach to controller methods. In a way, an action filter is like an interceptor and can insert your code in four places—before and after the action is executed and before and after the view result is executed. For our purposes, we need an action filter that kicks in right after the action methods returns. Here's the skeleton of such a filter:

public class ViewModelFillerAttribute : ActionFilterAttribute

{

    public override void OnActionExecuted(ActionExecutedContext filterContext)

    {

        var model = filterContext.Controller.ViewData.Model;

        // Apply changes to the view model object

        ...

    }

}


Related Content:

ARTICLE TOOLS

Comments
    There are no comments to display. Be the first one!
You must log on before posting a comment.

Are you a new visitor? Register Here

advertisement

advertisement

Windows is a trademark of the Microsoft group of companies. Windows IT Pro is used by Penton Media Inc. under license from owner.