Проблемы с зависимостями в преобразователях типов AutoMapper - PullRequest
1 голос
/ 15 ноября 2011

Я столкнулся с проблемой при использовании AutoMapper и Windsor. Я создал пользовательский преобразователь типов, который зависит от другого объекта, который можно разрешить из контейнера, но когда я пытаюсь использовать преобразователь в процессе отображения, создается исключение AutoMapper.AutoMapperMappingExa, утверждая, что в моем преобразователе типов нет конструктор по умолчанию.

Я воссоздал проблему в коде подтверждения концепции ниже:

using System;
using System.Reflection;
using AutoMapper;
using Castle.MicroKernel.Registration;
using Castle.MicroKernel.SubSystems.Configuration;
using Castle.Windsor;
using NUnit.Framework;

public class ObjectOne
{
    public string Name { get; set; }
    public string Description { get; set; }
}

public class ObjectTwo
{
    public string ObjName { get; set; }
    public string ObjDescr { get; set; }
}

public interface ILoggingService
{
    void Log(string message);
}

public class ConsoleLogger : ILoggingService
{
    public void Log(string message)
    {
        Console.WriteLine(message);
    }
}

public class MyObjectConvertor : ITypeConverter<ObjectOne, ObjectTwo>
{
    private readonly ILoggingService _loggingService;

    public MyObjectConvertor(ILoggingService loggingService)
    {
        if (loggingService == null) throw new ArgumentNullException("loggingService");
        _loggingService = loggingService;
    }

    public ObjectTwo Convert(ResolutionContext context)
    {
        _loggingService.Log(MethodBase.GetCurrentMethod().ToString());
        var source = (ObjectOne)context.SourceValue;
        return new ObjectTwo { ObjName = source.Name, ObjDescr = source.Description };
    }

    public void LogIt(string message)
    {
        _loggingService.Log(message);
    }
}

public class MappingContractsWindsorInstaller : IWindsorInstaller
{
    public void Install(IWindsorContainer container, IConfigurationStore store)
    {
        container.Register(
            Component.For<ILoggingService>().ImplementedBy<ConsoleLogger>(),
            Component.For<MyObjectConvertor>());
    }
}

[TestFixture]
public class MappingTester
{
    private IWindsorContainer container;

    [TestFixtureSetUp]
    public void SetupFixture()
    {
        container = new WindsorContainer();
        container.Install(new MappingContractsWindsorInstaller());
        Mapper.CreateMap<ObjectOne, ObjectTwo>().ConvertUsing<MyObjectConvertor>();
        Mapper.Configuration.ConstructServicesUsing(container.Resolve);
        Mapper.AssertConfigurationIsValid();
    }

    [Test]
    public void MyObjectConvertorReturnedWithLoggerInjectedOk()
    {   // Proof that the Convertor is returned from the 
        // container with the dependency fulfilled
        var conv = container.Resolve<MyObjectConvertor>();
        conv.LogIt("Hello World");
    }

    [Test]
    public void ObjectOneMapsToTwo()
    {
        var source = new ObjectOne()
                    {
                        Name = "Foo",
                        Description = "Bar"
                    };

        var result = Mapper.Map<ObjectOne, ObjectTwo>(source);
        Assert.That(result.ObjName == source.Name);
        Assert.That(result.ObjDescr == source.Description);
    }
}

При выполнении тестов во время ObjectOneMapsToTwo () выдается следующее исключение:

    Test 'MappingTester.ObjectOneMapsToTwo' failed: AutoMapper.AutoMapperMappingException : Trying to map ObjectOne to ObjectTwo.
Using mapping configuration for ObjectOne to ObjectTwo
Exception of type 'AutoMapper.AutoMapperMappingException' was thrown.
  ----> System.ArgumentException : Type 'MyObjectConvertor' does not have a default constructor
    at AutoMapper.MappingEngine.AutoMapper.IMappingEngineRunner.Map(ResolutionContext context)
    at AutoMapper.MappingEngine.Map(Object source, Type sourceType, Type destinationType, Action`1 opts)
    at AutoMapper.MappingEngine.Map[TSource,TDestination](TSource source)
    at AutoMapper.Mapper.Map[TSource,TDestination](TSource source)
    Class1.cs(99,0): at MappingTester.ObjectOneMapsToTwo()
    --ArgumentException
    at System.Linq.Expressions.Expression.New(Type type)
    at AutoMapper.DelegateFactory.<>c__DisplayClass1.<CreateCtor>b__0(Type t)
    at System.Collections.Concurrent.ConcurrentDictionary`2.GetOrAdd(TKey key, Func`2 valueFactory)
    at AutoMapper.DelegateFactory.CreateCtor(Type type)
    at AutoMapper.Mappers.ObjectCreator.CreateObject(Type type)
    at AutoMapper.MappingExpression`2.<ConvertUsing>b__1a[TTypeConverter]()
    at AutoMapper.DeferredInstantiatedConverter`2.Convert(ResolutionContext context)
    at AutoMapper.MappingExpression`2.<>c__DisplayClass15.<ConvertUsing>b__14(ResolutionContext context)
    at AutoMapper.Mappers.TypeMapObjectMapperRegistry.CustomMapperStrategy.Map(ResolutionContext context, IMappingEngineRunner mapper)
    at AutoMapper.Mappers.TypeMapMapper.Map(ResolutionContext context, IMappingEngineRunner mapper)
    at AutoMapper.MappingEngine.AutoMapper.IMappingEngineRunner.Map(ResolutionContext context)

Этот проект ссылается на следующее:

<packages>
  <package id="NUnit" version="2.5.10.11092" />
  <package id="Castle.Core" version="2.5.2" />
  <package id="Castle.Windsor" version="2.5.3" />
  <package id="AutoMapper" version="2.0.0" />
</packages>

Тест MyObjectConvertorReturnedWithLoggerInjectedOk () проходит, подтверждая, что преобразователь типов возвращается из контейнера с зависимостью, переданной в OK. Но когда Automapper пытается использовать конвертер, он выдает исключение.

Любая помощь по этому вопросу будет принята.

Заранее спасибо.

1 Ответ

0 голосов
/ 15 ноября 2011

На самом деле это ошибка в AutoMapper, исправленная после выпуска 2.0 и появившаяся в следующей версии 2.1. Вы можете снять ночные клубы, чтобы получить последнюю стабильную версию с AutoMapper.org

...