Integrating Automapper with an MVC Result Filter Integrating Automapper with an MVC Result Filter

Please note this is an excerpt from Chapter 9 of my ASP.NET MVC 5 with Bootstrap and Knockout.js book. In this chapter I provide a brief overview of the 5 different MVC filters and then over the next two chapters provide detail examples of each. The following post is leveraging the example of a Result Filter.


On a variety of actions inside your controllers you call the Automapper NuGet Package to convert from one model to another and you do not want to continue repeating this code each time.

Implement FilterAttribute with IResultFilter

Applying an MVC result filter to the action can execute the Automapper code after the action has been processed by the MVC framework and before the view is rendered.

Before I get to the example code, here is a quick summary of what an MVC Result Filter is:

Result filters provide two different functions that can be optionally implemented. The first is when the result has finished executing; for example, in an MVC controller once the view has been fully rendered and is ready to be returned from the server. The second is when the result is executing. This function would not have access to the final content.

Throughout the book, I was building upon an AuthorsController. The Index view would display a list of authors including pagination and sorting. The paging and sorting was accomplished by a class called QueryOptions and a list of the authors. These two properties are wrapped in another class called ResultList. This is the class that the Index view was bound to. These classes are not important for this example, but the background is required as the Result filter will be referencing them.

Installing the Automapper NuGet Package

Moving on with the Automapper Result filter. The first thing required is to install the Automapper NugGet Package. From the NuGet Package Manager Console, enter the following command to install the latest version: Install-Package AutoMapper. Next the filter itself needs to be created, I called it GenerateResultListFilterAttribute.

This class extends the FilterAttribute and implements the IResultFilter interface. In the constructor two Type parameters are accepted. The first is the source for the automapping. The second is the destination. Using these two types (and some reflection), the Automapper mapping is defined and executed. Below is the full source code for this class. Please note it references namespaces and classes from the sample project for my book.


using BootstrapIntroduction.Models;
using BootstrapIntroduction.ViewModels;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Web;
using System.Web.Mvc;
namespace BootstrapIntroduction.Filters
{
[AttributeUsage(AttributeTargets.Method)]
public class GenerateResultListFilterAttribute : FilterAttribute, IResultFilter
{
private readonly Type _sourceType;
private readonly Type _destinationType;
public GenerateResultListFilterAttribute(Type sourceType, Type destinationType)
{
_sourceType = sourceType;
_destinationType = destinationType;
}
public void OnResultExecuting(ResultExecutingContext filterContext)
{
var model = filterContext.Controller.ViewData.Model;
var resultListGenericType = typeof(ResultList<>).MakeGenericType(new Type[] { _destinationType });
var srcGenericType = typeof(List<>).MakeGenericType(new Type[] { _sourceType });
var destGenericType = typeof(List<>).MakeGenericType(new Type[] { _destinationType });
AutoMapper.Mapper.CreateMap(_sourceType, _destinationType);
var viewModel = AutoMapper.Mapper.Map(model, srcGenericType, destGenericType);
var queryOptions = filterContext.Controller.ViewData.ContainsKey("QueryOptions") ?
filterContext.Controller.ViewData["QueryOptions"] :
new QueryOptions();
var resultList = Activator.CreateInstance(resultListGenericType, viewModel, queryOptions);
filterContext.Controller.ViewData.Model = resultList;
}
public void OnResultExecuted(ResultExecutedContext filterContext)
{
}
}
}

Leveraging the OnResultExecuting

In the OnResultExecuting function, the source model is extracted into a variable. This would be set from the controller when calling: return View(model). Then, using some reflection, a new ResultList object is created that specifies the destination type of the list (of authors). At the end of this function, the new ResultList object is set that the view is data bound to. This replaces the previous model that was passed to the view in the controller.

To use this attribute, it needs to be applied to an action like the following example. This is an extract of the Index action from the AuthorsController that was built during the various examples throughout my book.


// GET: Authors
[GenerateResultListFilterAttribute(typeof(Author), typeof(AuthorViewModel))]
public ActionResult Index([Form] QueryOptions queryOptions)
{
var authors = authorService.Get(queryOptions);
ViewData["QueryOptions"] = queryOptions;
return View(authors);
}

As you can see by the attribute definition, the Result filter will map from the Author model to the AuthorViewModel. From the controller, a list of Author models are supplied to the view. When the result filter runs, it will replace the list of Author models with a ResultList that includes a list of AuthorViewModels. The full source code is available in my ASP.NET MVC 5 with Bootstrap and Knockout.js book.

Published on May 4, 2015

Tags: ASP.NET MVC and Web API Tutorial | automapper

Related Posts

Did you enjoy this article? If you did here are some more articles that I thought you will enjoy as they are very similar to the article that you just finished reading.

Tutorials

Learn how to code in HTML, CSS, JavaScript, Python, Ruby, PHP, Java, C#, SQL, and more.

No matter the programming language you're looking to learn, I've hopefully compiled an incredible set of tutorials for you to learn; whether you are beginner or an expert, there is something for everyone to learn. Each topic I go in-depth and provide many examples throughout. I can't wait for you to dig in and improve your skillset with any of the tutorials below.