Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to use the new IValueResolver of AutoMapper?

Tags:

I am at a loss as to how to use the new IValueResolver interface in the new version of AutoMapper. Perhaps I used them improperly in the previous versions of AutoMapper...

I have a lot of model classes, some of them are generated from several databases on several database servers, using sqlmetal.

Some of these classes has a string property, PublicationCode, which identifies which publication the subscription, or offer, or invoice, or whatever it is, belongs to.

The publication can exist in either of two systems (the old and the new system), hence I have a bool property on the destination model classes which tells whether the publication is in the old or the new system.

Using the old version (<5?) of AutoMapper, I used a ValueResolver<string, bool> which took the PublicationCode as an input parameter, and returned a bool indicating the location of the publication (old or new system).

With the new version (5+?) of AutoMapper, this seems to no longer be possible. The new IValueResolver requires a unique implementation of each and every combination of source and destination models that I have, where src.PublicationCode needs to be resolved into a dst.IsInNewSystem.

Am I just trying to use the value resolvers in the wrong way? Is there a better way? The main reason I would like to use a resolver is that I would prefer to have services injected into the constructor, and not having to use DependencyResolver and the like in the code (I'm using Autofac).

Currently, I use it in the following way:

// Class from Linq-to-SQL, non-related properties removed.
public class FindCustomerServiceSellOffers {
    public string PublicationCode { get; set; }
}

This is one of several data model classes I have, which contains a PublicationCode property). This particular class is mapped to this view model:

public class SalesPitchViewModel {
    public bool IsInNewSystem { get; set; }
}

The mapping definition for these two classes is (where expression is an IProfileExpression), non-related mappings removed:

expression.CreateMap<FindCustomerServiceSellOffers, SalesPitchViewModel>()
          .ForMember(d => d.IsInNewSystem, o => o.ResolveUsing<PublicationSystemResolver>().FromMember(s => s.PublicationCode));

And the resolver:

public class PublicationSystemResolver : ValueResolver<string, bool>
{
    private readonly PublicationService _publicationService;
    public PublicationSystemResolver(PublicationService publicationService)
    {
        _publicationService = publicationService;
    }

    protected override bool ResolveCore(string publicationCode)
    {
        return _publicationService.IsInNewSystem(publicationCode);
    }
}

And the use of the mapper:

var result = context.FindCustomerServiceSellOffers.Where(o => someCriteria).Select(_mapper.Map<SalesPitchViewModel>).ToList();
like image 976
PaddySe Avatar asked Jul 11 '16 12:07

PaddySe


People also ask

How do I use AutoMapper to list a map?

Once you have your types, and a reference to AutoMapper, you can create a map for the two types. Mapper. CreateMap<Order, OrderDto>(); The type on the left is the source type, and the type on the right is the destination type.

How do I test AutoMapper configuration?

To test our configuration, we simply create a unit test that sets up the configuration and executes the AssertConfigurationIsValid method: var configuration = new MapperConfiguration(cfg => cfg. CreateMap<Source, Destination>()); configuration. AssertConfigurationIsValid();


1 Answers

You can create a more general value resolver by implementing IMemberValueResolver<object, object, string, bool> and using that in your mapping configuration. You can provide a source property resolution function as before:

public class PublicationSystemResolver : IMemberValueResolver<object, object, string, bool>
{
    private readonly PublicationService _publicationService;

    public PublicationSystemResolver(PublicationService publicationService)
    {
        this._publicationService = publicationService;
    }

    public bool Resolve(object source, object destination, string sourceMember, bool destMember, ResolutionContext context)
    {
        return _publicationService.IsInNewSystem(sourceMember);
    }
}



cfg.CreateMap<FindCustomerServiceSellOffers, SalesPitchViewModel>()
    .ForMember(dest => dest.IsInNewSystem,
        src => src.ResolveUsing<PublicationSystemResolver, string>(s => s.PublicationCode));
like image 136
Rhumborl Avatar answered Sep 25 '22 03:09

Rhumborl