tags:

views:

97

answers:

1

For my objects, I am using Csla, which has a BrokenRulesCollection property. I would like to convert that to my own DTO which has StatusMessages property.

I created my own resolver:

public class BrokenRulesCollectionResolver : ValueResolver<Csla.Validation.BrokenRulesCollection, StatusMessageList>
{
    protected override StatusMessageList ResolveCore(Csla.Validation.BrokenRulesCollection source)
    {
        var messageList = new StatusMessageList();
        messageList.ReadBrokenRules(source);
        return messageList;
    }
}

And in the mapping, I'm letting it know which resolver to use:

        Mapper.CreateMap<DomainObjects.Members.IMemberRegistration, DTO.Members.MemberRegistrationForm>()
            .ForMember(src => src.StatusMessages, opt => opt.ResolveUsing <BrokenRulesCollectionResolver>());

However, when I try to do the mapping:

       return Mapper.Map<DomainObjects.Members.IMemberRegistration, DTO.Members.MemberRegistrationForm>(memberRegistration);

I get the following error:

Value supplied is of type Csla.Validation.BrokenRulesCollection but expected Favs.DomainObjects.Members.MemberRegistration. Change the value resolver source type, or redirect the source value supplied to the value resolver using FromMember.

Any suggestions?

Edit:

As a follow up, I have also tried to create a convert but still get the same message:

public class BrokenRulesCollectionConverter : ITypeConverter<Csla.Validation.BrokenRulesCollection, StatusMessageList>
{
    public StatusMessageList Convert(ResolutionContext context)
    {
        var test = new StatusMessageList();
        test.ReadBrokenRules((Csla.Validation.BrokenRulesCollection)context.SourceValue);
        return test;
    }
}

And configure it as follows:

        Mapper.CreateMap<Csla.Validation.BrokenRulesCollection, StatusMessageList>()
            .ConvertUsing<BrokenRulesCollectionConverter>();
+2  A: 

The instance that AutoMapper passes into ResolveCore here is not the BrokenRulesCollection - AutoMapper doesn't know which property of the IMemberRegistration to get that from. When you use a custom resolver, it gets an instance of the same object you are trying to map.

It should work if you rewrite your first class like so:

public class BrokenRulesCollectionResolver :
    ValueResolver<DomainObjects.Members.IMemberRegistration, StatusMessageList>
{
    protected override StatusMessageList ResolveCore(
        DomainObjects.Members.IMemberRegistration source)
    {
        var messageList = new StatusMessageList();
        messageList.ReadBrokenRules(source.BrokenRules);
        return messageList;
    }
}

Note - I'm assuming that the member you want to map on IMemberRegistration is a property called BrokenRules. Change this to whatever applies.

Edit - you can also do what the message suggests and use FromMember:

Mapper.CreateMap<DomainObjects.Members.IMemberRegistration,
    DTO.Members.MemberRegistrationForm>()
        .ForMember(src => src.StatusMessages,
            opt => opt
                .ResolveUsing<BrokenRulesCollectionResolver>()
                .FromMember(r => r.BrokenRules));

Again, this assumes the property is named BrokenRules. You have to tell AutoMapper, it can't guess in this case.

Aaronaught
This works great! Is it possible to declare a Resolver or Converter between the two types of lists? Lots of my objects have the BrokenRulesCollection and need to convert to my DTO's StatusMessageList. I would like to avoid having a different Resolver for each pair.
Andy
@Andy: My second example can be used with your original resolver which only depends on the `BrokenRulesCollection` (since you tell AutoMapper which specific property to use with `FromMember`). You can use the same resolver for every composite object, you just have to make sure to add the `FromMember` to each mapping.
Aaronaught