Sunday, June 3, 2012

Pagination with AutoMapper

I recently posted a method of using AutoMapper in an ActionResult (http://bzbetty.blogspot.co.nz/2012/06/thoughts-on-actionfilters.html).  This became an issue when I was trying to return a paginated model to the view, as I wanted to do pagination in the database (on the entities) but AutoMapper had no idea how to map the IPagination result to the ViewModel.

Result - Build a custom IObjectMapper to do the mapping


Resulting Action

[AutoMap(typeof(EventListViewModel))]
public ActionResult Index(int? page)
{
page = page ?? 1;
var entities = //load data from database
.AsPagination(page.Value, 20); //pagination method from MVC Contrib
return View(entities);
}
view raw automap.cs hosted with ❤ by GitHub
IObjectMapper
public class PaginationMapper : IObjectMapper
{
private IMappingEngineRunner _mapper;
public T Map<T>(object source)
{
TypeMap typeMap = _mapper.ConfigurationProvider.FindTypeMapFor(source, source.GetType(), typeof(T));
MappingOperationOptions mappingOperationOptions = new MappingOperationOptions();
ResolutionContext resolutionContext = new ResolutionContext(typeMap, source, source.GetType(), typeof(T), mappingOperationOptions);
return (T)_mapper.Map(resolutionContext);
}
public PagedList<T> CreatePagedList<T>(IPagination source)
{
var result = Activator.CreateInstance<PagedList<T>>();
result.TotalItems = source.TotalItems;
result.TotalPages = source.TotalPages;
result.HasNextPage = source.HasNextPage;
result.HasPreviousPage = source.HasPreviousPage;
result.PageNumber = source.PageNumber;
result.PageSize = source.PageSize;
result.FirstItem = source.FirstItem;
result.LastItem = source.LastItem;
foreach (var item in source)
{
result.Add(Map<T>(item));
}
return result;
}
public object Map(ResolutionContext context, IMappingEngineRunner mapper)
{
_mapper = mapper;
Type destinationType = context.DestinationType.GetGenericArguments()[0];
var method = typeof(PaginationMapper).GetMethod("CreatePagedList").MakeGenericMethod(destinationType);
return method.Invoke(this, new[] { context.SourceValue });
}
public bool IsMatch(ResolutionContext context)
{
return typeof(IPagination).IsAssignableFrom(context.SourceType) && typeof(IPagination).IsAssignableFrom(context.DestinationType);
}
}
view raw pagination.cs hosted with ❤ by GitHub