简体   繁体   English

如何在Ninject.Web.Mvc中使用AutoMapper?

[英]How do I use AutoMapper with Ninject.Web.Mvc?

Setup 设定

I have an AutoMapperConfiguration static class that sets up the AutoMapper mappings: 我有一个AutoMapperConfiguration静态类,用于设置AutoMapper映射:

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

where IdToEntityConverter<T> is a custom ITypeConverter that looks like this: 其中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 takes an IRepository in its constructor in order to convert an ID back to the actual entity by hitting up the database. IdToEntityConverter在其构造函数中获取IRepository ,以便通过命中数据库将ID转换回实际实体。 Notice how it doesn't have a default constructor. 请注意它没有默认构造函数。

In my ASP.NET's Global.asax , this is what I have for OnApplicationStarted() and CreateKernel() : 在我的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;
}

So OnApplicationCreated() will call AutoMapperConfiguration.SetupMappings() to set up the mappings and CreateKernel() will bind an instance of NHibRepository to the IRepository interface. 因此OnApplicationCreated()将调用AutoMapperConfiguration.SetupMappings()来设置映射, CreateKernel()NHibRepository的实例绑定到IRepository接口。

Problem 问题

Whenever I run this code and try to get AutoMapper to convert a category ID back to a category entity, I get an AutoMapperMappingException that says no default constructor exists on IdToEntityConverter . 每当我运行此代码并尝试让AutoMapper将类别ID转换回类别实体时,我会得到一个AutoMapperMappingException ,它表示IdToEntityConverter上不存在默认构造IdToEntityConverter

Attempts 尝试

  1. Added a default constructor to IdToEntityConverter . IdToEntityConverter添加了默认构造IdToEntityConverter Now I get a NullReferenceException , which indicates to me that the injection isn't working. 现在我得到一个NullReferenceException ,它向我表明注入不起作用。

  2. Made the private _repo field into a public property and added the [Inject] attribute. 将private _repo字段设置为公共属性并添加[Inject]属性。 Still getting NullReferenceException . 仍然得到NullReferenceException

  3. Added the [Inject] attribute on the constructor that takes an IRepository . 在带有IRepository的构造函数上添加了[Inject]属性。 Still getting NullReferenceException . 仍然得到NullReferenceException

  4. Thinking that perhaps Ninject can't intercept the AutoMapperConfiguration.SetupMappings() call in OnApplicationStarted() , I moved it to something that I know is injecting correctly, one of my controllers, like so: 想想Ninject可能无法拦截OnApplicationStarted()AutoMapperConfiguration.SetupMappings()调用,我把它移动到我知道注入正确的东西,我的一个控制器,如下所示:

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

    Still getting NullReferenceException . 仍然得到NullReferenceException

Question

My question is, how do I get Ninject to inject an IRepository into IdToEntityConverter ? 我的问题是,如何让Ninject将一个IRepository注入IdToEntityConverter

@ozczecho's answer is spot-on, but I'm posting the Ninject version of the code because it has one little caveat that caught us for a while: @ ozczecho的回答是现实的,但是我发布了Ninject版本的代码,因为它有一个小小的警告,抓住了我们一段时间:

IKernel kernel = null; // Make sure your kernel is initialized here

Mapper.Initialize(map =>
{
    map.ConstructServicesUsing(t => kernel.Get(t));
});

You can't just pass in kernel.Get to map.ConstructServicesUsing because that method has a params parameter in addition to the Type. 你不能只将kernel.Get传递给map.ConstructServicesUsing因为除了Type之外,该方法还有一个params参数。 But since params are optional, you can just create the lambda expression to generate an anonymous function to get you what you need. 但是因为params是可选的,所以你可以创建lambda表达式来生成一个匿名函数来获得你需要的东西。

You have to give AutoMapper access to the DI container. 您必须授予AutoMapper访问DI容器的权限。 We use StructureMap, but I guess the below should work with any DI. 我们使用StructureMap,但我想下面的内容应该适用于任何DI。

We use this (in one of our Bootstrapper tasks)... 我们使用它(在我们的一个Bootstrapper任务中)......

    private IContainer _container; //Structuremap container

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM