Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Problem with Automapper and Windsor

I have a problem with Automapper when I try use custom resolver which uses dependency injection.

I have the following model:

public class User : Entity
{
    public virtual string Name { get; set; }
    public virtual Country Country { get; set; }
}

public class Country : Entity
{
    public virtual string Name { get; set; }
}

and the following view model:

public class RegistrationViewModel
{
    [Required]        
    public string Name { get; set; }

    public int CountryId { get; set; }

    public IEnumerable<Country> Countries { get; set; }
}

in order to map I use the following code:

Mapper.Map(registrationViewModel, user);

earlier I register the following:

Mapper.Reset();
container = new WindsorContainer();
container.AddFacility<FactorySupportFacility>();
container.Register(Component.For<ISession>().
                               UsingFactoryMethod(() => NHibernateSessionFactory.RetrieveSession()).
                               LifeStyle.Is(LifestyleType.Transient));
container.Register(Component.For(typeof(LoadingEntityResolver<>)).ImplementedBy(typeof(LoadingEntityResolver<>)).LifeStyle.Transient);
 Mapper.Initialize(x =>
      {
           x.AddProfile<BasicProfile>();
           x.ConstructServicesUsing(container.Resolve);
      });

My BasicProfile is the following:

public class BasicProfile : Profile
{
    public const string VIEW_MODEL = "MyBasicProfile";

    public override string ProfileName
    {
        get { return VIEW_MODEL; }
    }

    protected override void Configure()
    {
        CreateMaps();
    }

    private void CreateMaps()
    {
        CreateMap<RegistrationViewModel, User>()
           .ForMember(dest => dest.Country, _ => _.ResolveUsing<LoadingEntityResolver<Country>>().FromMember(src => src.CountryId))
           );

    }
}

The custom resolver is done in the following way:

public class LoadingEntityResolver<TEntity> : ValueResolver<int, TEntity>
    where TEntity: Entity
{
    private readonly ISession _session;

    public LoadingEntityResolver(ISession session)
    {
        _session = session;
    }

   protected override TEntity ResolveCore(int source)
   {
       return _session.Load<TEntity>(source);
   }

}

When the mapping code is being run I get the following exception:

AutoMapper.AutoMapperMappingException : Trying to map ViewModels.RegistrationViewModel to Models.User. Using mapping configuration for ViewModels.RegistrationViewModel to Models.User Exception of type 'AutoMapper.AutoMapperMappingException' was thrown. ----> AutoMapper.AutoMapperMappingException : Trying to map ViewModels.RegistrationViewModel to LModels.Country. Using mapping configuration for ViewModels.RegistrationViewModel to Models.User Destination property: Country Exception of type 'AutoMapper.AutoMapperMappingException' was thrown. ----> System.ArgumentException : Type 'Mapping.LoadingEntityResolver`1[Models.Country]' does not have a default constructor

I have no idea what may be wrong. It is probably something with constructing the resolver. When I try the following there is no problem:

var resolver = container.Resolve<LoadingEntityResolver<Country>>();

Assert.IsInstanceOf<LoadingEntityResolver<Country>>(resolver);

I would be greatfull for any help.

Best regards
Lukasz

like image 697
GUZ Avatar asked Oct 10 '22 17:10

GUZ


1 Answers

You have some pretty hefty DI stuff going on here :-) I would avoid having AutoMapper resolve entities from a database or whatever. Makes the code difficult to understand and following objects lifetime could become a nightmare.

Anyway, to fix your problem simply swap the order from (wrong):

Mapper.Initialize(x =>
{
    x.AddProfile<BasicProfile>();
    x.ConstructServicesUsing(container.Resolve);
});

to (correct):

Mapper.Initialize(x =>
{
    x.ConstructServicesUsing(container.Resolve);
    x.AddProfile<BasicProfile>();
});
like image 196
Darin Dimitrov Avatar answered Nov 03 '22 05:11

Darin Dimitrov