Как использовать AutoMapper с Ninject.Web.Mvc?
Настройка
У меня есть статический класс 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 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;
}
So OnApplicationCreated()
вызовет AutoMapperConfiguration.SetupMappings()
, чтобы настроить сопоставления, а CreateKernel()
привяжет экземпляр NHibRepository
к интерфейсу IRepository
.
Проблема
Всякий раз, когда я запускаю этот код и пытаюсь получить AutoMapper для преобразования идентификатора категории обратно в объект категории, я получаю AutoMapperMappingException
, который говорит, что конструктор по умолчанию не существует на IdToEntityConverter
.
Попытки
-
Добавлен конструктор по умолчанию в IdToEntityConverter
. Теперь я получаю NullReferenceException
, что указывает на то, что инъекция не работает.
-
Создал частный _repo
в публичное свойство и добавил атрибут [Inject]
. Все еще получаю NullReferenceException
.
-
Добавлен атрибут [Inject]
в конструкторе, который принимает IRepository
. Все еще получаю NullReferenceException
.
-
Думая, что, возможно, Ninject не может перехватить вызов AutoMapperConfiguration.SetupMappings()
в OnApplicationStarted()
, я переместил его в то, что, как я знаю, правильно вводит, один из моих контроллеров, например:
public class RepositoryController : Controller
{
static RepositoryController()
{
AutoMapperConfiguration.SetupMappings();
}
}
По-прежнему получать NullReferenceException
.
Вопрос
Мой вопрос: как мне получить Ninject для ввода IRepository
в IdToEntityConverter
?
Ответы
Ответ 1
Вы должны предоставить AutoMapper доступ к контейнеру DI. Мы используем StructureMap, но я думаю, что нижеследующее должно работать с любым DI.
Мы используем это (в одной из наших задач Bootstrapper)...
private IContainer _container; //Structuremap container
Mapper.Initialize(map =>
{
map.ConstructServicesUsing(_container.GetInstance);
map.AddProfile<MyMapperProfile>();
}
Ответ 2
@ozczecho ответ на месте, но я отправляю версию кода Ninject, потому что у него есть одно небольшое предостережение, которое нас поймало какое-то время:
IKernel kernel = null; // Make sure your kernel is initialized here
Mapper.Initialize(map =>
{
map.ConstructServicesUsing(t => kernel.Get(t));
});
Вы не можете просто передать kernel.Get
в map.ConstructServicesUsing
, потому что этот метод имеет параметр params
в дополнение к типу. Но поскольку параметры необязательны, вы можете просто создать выражение лямбда для создания анонимной функции, чтобы получить то, что вам нужно.