views:

47

answers:

1

If I have some classes that implement the same interface, so they all contain the same property. Is there a way to add a formatter to these properties? I only found the possibility to add a formatter to a specific property type.

Here's some code that should clarify what I mean:

public interface ITaggable
{
    IList<string> Tags { get; set; }
}

public class Post : ITaggable
{
    public IList<string> Tags { get; set; }
    public IList<string> Categories { get; set; }
    ...
}

public class Page : ITaggable
{
    public IList<string> Tags { get; set; }
    ....
}

I'd like to map these to view models that look something like this:

public class PostViewModel
{
    public string Tags { get; set; }
    public IList<string> Categories { get; set; }
    ...
}

public class PageViewModel
{
    public string Tags { get; set; }
    ...
}

If a Post has the tags "foo" and "bar", then the PostViewModel's Tags property should contain the string "foo, bar". Categories should remain an IList<string>.

I could accomplish this by creating a custom formatter and then add it on every mapping, like this:

protected override void Configure()
{
    CreateMap<Post, PostViewModel>()
        .ForMember(x => x.Tags, opt => opt.AddFormatter<TagsFormatter>());
    CreateMap<Page, PageViewModel>()
        .ForMember(x => x.Tags, opt => opt.AddFormatter<TagsFormatter>());
}

But I'd like to do something like this (this code doesn't work ;-)

protected override void Configure()
{
    ForSourceType<ITaggable>()
        .ForMember(x => x.Tags, opt => opt.AddFormatter<TagsFormatter>());

    CreateMap<Post, PostViewModel>();
    CreateMap<Page, PageViewModel>();
}
A: 

It's not exactly an answer to the question I was asking, but a solution to the problem:

I built a TagsFormatter that checks the name of the property for "Tags":

public class TagsFormatter : IValueFormatter
{
    public string FormatValue(ResolutionContext context)
    {
        if (context.MemberName.Equals("Tags", StringComparison.InvariantCultureIgnoreCase))
        {
            var tags = context.SourceValue as IList<string>;
            if (tags != null)
                return String.Join(", ", tags);
        }
        return context.SourceValue.ToString();
    }
}

In the configuration I can then register this Formatter for all mappings:

public class ViewModelProfile : AutoMapper.Profile
{
    protected override void Configure()
    {
        ForSourceType<IList<string>>().AddFormatter<TagsFormatter>();

        CreateMap<Post, PostViewModel>();
        CreateMap<Page, PageViewModel>();
    }
}
Dave