2

I have e.g. the following code that queries a list of DTOs, and maps that to a list of viewmodels. I would like to have my container resolve these viewmodels, instead of AutoMapper simply instantiating them without any injection.

using (var db = new AppDbContext())
{
    var types = await db.ApptTypes
        .Where(t => t.BranchId == branchId && (includeDeleted || !t.IsDeleted))
        .Include(e => e.CreatedBy)
        .Include(e => e.CreatedAt)
        .Include(e => e.Org)
        .Include(e => e.Branch)
        .ToListAsync(cancellationToken);
    return Mapper.Map<IEnumerable<ApptTypeDetailViewModel>>(types);
}
ProfK
  • 49,207
  • 121
  • 399
  • 775
  • Interesting idea. With AutoMapper's new(er) instance-based mapping you may be able to inject the required mapping configuration. Although I think the problem is that the destination type must always be known at compile time. – Gert Arnold Feb 04 '17 at 20:00
  • @GertArnold The destination type is known at compile time, I just need to find a way to tell AutoMapper how to instantiate it, i.e. resolve it with Unity. – ProfK Feb 05 '17 at 03:52
  • Then I don't understand what you mean by *I would like to have my container resolve these viewmodels*. Isn't that a run-time resolution of view model types? – Gert Arnold Feb 05 '17 at 22:35
  • @GertArnold Yes, it is a runtime resolution of the viewmodels, but AutoMapper just calls the default ctor, it doesn't call `container.Resolve` to instantiate the viewmodels. I have found a some info though and may have an answer soon. AutoMapper is runtime instantiation, just by the way, so why not runtime resolution> – ProfK Feb 06 '17 at 01:59

1 Answers1

0

Thanks to this answer, I have found a neat and fairly reliable way of achieving what I want. The main process looks like this:

class Program
{
    private static IUnityContainer _container;
    static void Main(string[] args)
    {
        var boot = new Bootstrapper();
        boot.Run();
        _container = boot.Container;

        InitMaps(_container);

        var dto = new Dto {Id = 418, Name = "Abrahadabra"};
        var model = Mapper.Map<ViewModel>(dto);
    }

    private static void InitMaps(IUnityContainer container)
    {
        Mapper.Initialize(cfg =>
        {
            cfg.CreateMap<Dto, ViewModel>()
                .ConstructUsing(f => UnityObjectFactoty.GetInstance<ViewModel>(container));
        });
    }
}

And the factory:

class UnityObjectFactoty
{
    public static TObject GetInstance<TObject>(IUnityContainer container)
    {
        return container.Resolve<TObject>();          
    }
}

Where the viewmodel is:

public class ViewModel
{
    public ViewModel(IService service)
    {
        _service = service;
    }

    private IService _service;
    public int Id { get; set; }
    public string Name { get; set; }
}

All that remains is to provide ctor parameters not resolved by the container, but that is not a requirement in my use case of this pattern.

Community
  • 1
  • 1
ProfK
  • 49,207
  • 121
  • 399
  • 775