Как мне использовать AutoMapper с Ninject.Web.Mvc? - PullRequest
12 голосов
/ 02 ноября 2010

Настройка

У меня есть AutoMapperConfiguration статический класс, который устанавливает сопоставления AutoMapper:

static class AutoMapperConfiguration()
{
    internal static void SetupMappings()
    {
        Mapper.CreateMap<long, Category>.ConvertUsing<IdToEntityConverter<Category>>();
    }
}

, где IdToEntityConverter<T> - это пользовательский ITypeConverter, который выглядит следующим образом:

class IdToEntityConverter<T> : ITypeConverter<long, T> where T : Entity
{
    private readonly IRepository _repo;

    public IdToEntityConverter(IRepository repo)
    {
        _repo = repo;
    }

    public T Convert(ResolutionContext context)
    {
        return _repo.GetSingle<T>(context.SourceValue);
    }
}

IdToEntityConverter принимает IRepository в своем конструкторе, чтобы преобразовать идентификатор обратно в реальную сущность, ударив по базе данных. Обратите внимание, что у него нет конструктора по умолчанию.

В моем ASP.NET Global.asax это то, что у меня есть для OnApplicationStarted() и CreateKernel():

protected override void OnApplicationStarted()
{
    // stuff that's required by MVC
    AreaRegistration.RegisterAllAreas();
    RegisterRoutes(RouteTable.Routes);

    // our setup stuff
    AutoMapperConfiguration.SetupMappings();
}

protected override IKernel CreateKernel()
{
    var kernel = new StandardKernel();
    kernel.Bind<IRepository>().To<NHibRepository>();

    return kernel;
}

Таким образом, OnApplicationCreated() вызовет AutoMapperConfiguration.SetupMappings() для установки сопоставлений, а CreateKernel() свяжет экземпляр NHibRepository с интерфейсом IRepository.

Проблема

Всякий раз, когда я запускаю этот код и пытаюсь заставить AutoMapper преобразовать идентификатор категории обратно в сущность категории, я получаю AutoMapperMappingException, который говорит, что в IdToEntityConverter не существует конструктора по умолчанию.

Попытка

  1. Добавлен конструктор по умолчанию для IdToEntityConverter. Теперь я получаю NullReferenceException, который указывает мне, что инъекция не работает.

  2. Превратил приватное поле _repo в публичное свойство и добавил атрибут [Inject]. Все еще получаю NullReferenceException.

  3. Добавлен атрибут [Inject] в конструкторе, который принимает IRepository. Все еще получаю NullReferenceException.

  4. Думая, что, возможно, Ninject не сможет перехватить вызов AutoMapperConfiguration.SetupMappings() в OnApplicationStarted(), я переместил его в то, что, как я знаю, правильно вводит, в один из моих контроллеров, например:

    public class RepositoryController : Controller
    {
        static RepositoryController()
        {
            AutoMapperConfiguration.SetupMappings();
        }
    }
    

    Все еще получаю NullReferenceException.

Вопрос

Мой вопрос: как заставить Ninject ввести IRepository в IdToEntityConverter?

Ответы [ 2 ]

11 голосов
/ 25 апреля 2012

@ ozczecho ответ точен, но я выкладываю версию кода Ninject, потому что в ней есть одна небольшая оговорка, которая нас на некоторое время застала:от kernel.Get до map.ConstructServicesUsing, поскольку этот метод имеет параметр params в дополнение к типу.Но так как params являются необязательными, вы можете просто создать лямбда-выражение, чтобы сгенерировать анонимную функцию, чтобы получить то, что вам нужно.

8 голосов
/ 02 ноября 2010

Вы должны предоставить AutoMapper доступ к контейнеру DI.Мы используем StructureMap, но я предполагаю, что приведенное ниже должно работать с любым DI.

Мы используем это (в одной из наших задач Bootstrapper) ...

    private IContainer _container; //Structuremap container

    Mapper.Initialize(map =>
    {
        map.ConstructServicesUsing(_container.GetInstance);
        map.AddProfile<MyMapperProfile>();
    }
...