I am using Troy Goode's PagedList to provide paging information in my WebApi. His package returns an IPagedList that implements IEnumerable but also contains custom properties such as IsLastPage, PageNumber, PageCount, etc.
When you try to return this class from a WebApi controller method (such as the GET), the Enumerable is serialized, but the custom properties are not. So, I thought I would use AutoMapper and write a custom type converter to convert to a class such as this:
public class PagedViewModel<T>
{
public int FirstItemOnPage { get; set; }
public bool HasNextPage { get; set; }
public bool HasPreviousPage { get; set; }
public bool IsFirstPage { get; set; }
public bool IsLastPage { get; set; }
public int LastItemOnPage { get; set; }
public int PageCount { get; set; }
public int PageNumber { get; set; }
public int PageSize { get; set; }
public int TotalItemCount { get; set; }
public IEnumerable<T> rows { get; set; }
}
Since I move the Enumerable into a distinct property, the serialization handles it perfectly. So, I sat down and wrote a custom type converter like this:
public class PagedListTypeConverter<T> : ITypeConverter<IPagedList<T>, PagedViewModel<T>>
{
public PagedViewModel<T> Convert(ResolutionContext context)
{
var source = (IPagedList<T>)context.SourceValue;
return new PagedViewModel<T>()
{
FirstItemOnPage = source.FirstItemOnPage,
HasNextPage = source.HasNextPage,
HasPreviousPage = source.HasPreviousPage,
IsFirstPage = source.IsFirstPage,
IsLastPage = source.IsLastPage,
LastItemOnPage = source.LastItemOnPage,
PageCount = source.PageCount,
PageNumber = source.PageNumber,
PageSize = source.PageSize,
TotalItemCount = source.TotalItemCount,
rows = source
};
}
}
And then set it up in my configuration like this:
Mapper.CreateMap<IPagedList<Department>, PagedViewModel<Department>>().ConvertUsing(new PagedListTypeConverter<Department>());
But, when I try to call it like this:
var x = Mapper.Map<IPagedList<Department>, PagedViewModel<Department>>(departments);
I get this error:
Missing type map configuration or unsupported mapping.
Mapping types: IPagedList
1 -> PagedViewModel
1 PagedList.IPagedList1[[Provision.DomainObjects.Department, Provision.DomainObjects, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]] -> Provision.DomainObjects.PagedViewModel
1[[Provision.DomainObjects.Department, Provision.DomainObjects, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]]Destination path: PagedViewModel`1
Source value: PagedList.StaticPagedList`1[Provision.DomainObjects.Department]
How can I make this work?
AutoMapper supports polymorphic arrays and collections, such that derived source/destination types are used if found.
AutoMapper in C# is a library used to map data from one object to another. It acts as a mapper between two objects and transforms one object type into another. It converts the input object of one type to the output object of another type until the latter type follows or maintains the conventions of AutoMapper.
The ResolutionContext contains all of the contextual information for the current resolution operation, such as source type, destination type, source value and so on.
After pulling my hair out, I finally figured this one out. There isn't anything at all wrong with the code. It turned out to be a threading issue where the configured mappings were getting cleared out. The code above is the proper way to do what I wanted. I am leaving this here so that I can point another question to it for others who need to do the same thing.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With