【问题标题】:AutoMapper not instantiating IMappingEngine using SimpleInjector and WebApi2AutoMapper 不使用 SimpleInjector 和 WebApi2 实例化 IMappingEngine
【发布时间】:2015-11-18 19:32:19
【问题描述】:

我开始在我的项目(WebApi2,框架 4.5.1)中使用 AutoMapper(来自 Nuget 的最新版本)并使用 SimpleInjector(来自 Nuget 的最新版本)。

我的问题是我不知道如何配置 SimpleInjector 以通过构造函数将 IMappingEngine 注入我的模型。

现在我遇到了错误: 未映射的属性:MappingEngine

我正在使用 IMappingEngine 接口。

我有一个包含所有 Mapper.CreateMap 的 AutoMapperProfile 类

AutoMapperConfig 示例

public class WebApiAutomapperProfile : Profile
{
    /// <summary>
    /// The configure.
    /// </summary>
    protected override void Configure()
    {
        this.CreateMap<Entity, EntityModel>();
    }
}

模型接收 IMappingEngine 的原因是某些映射属性内部有其他映射。

Global.asax(方法 Application_Start())我正在调用:

 GlobalConfiguration.Configure(WebApiConfig.Register);

 webApiContainer = new Container();

 webApiContainer.Options.DefaultScopedLifestyle = new WebApiRequestLifestyle();

 IocConfig.RegisterIoc(GlobalConfiguration.Configuration, webApiContainer);

IocConfig.cs

public static class IocConfig
{
    public static void RegisterIoc(HttpConfiguration config, Container container)
    {
        InstallDependencies(container);
        RegisterDependencyResolver(container);
    }

    private static void InstallDependencies(Container container)
    {
        new ServiceInstallerSimpleInjector().Install(container);
    }

    private static void RegisterDependencyResolver(Container container)
    {
        GlobalConfiguration.Configuration.DependencyResolver = new SimpleInjectorWebApiDependencyResolver(container);
    }

ServiceInstallerSimpleInjector

public class ServiceInstallerSimpleInjector : IServiceInstallerSimpleInjector
{
    // Automapper registrations
    container.Register(typeof(ITypeMapFactory), typeof(TypeMapFactory), Lifestyle.Scoped);
    container.RegisterCollection<IObjectMapper>(MapperRegistry.Mappers);

    var configurationRegistration = Lifestyle.Scoped.CreateRegistration<ConfigurationStore>(container);
    container.AddRegistration(typeof(IConfiguration), configurationRegistration);
    container.AddRegistration(typeof(IConfigurationProvider), configurationRegistration);

    // The initialization runs all the map creation once so it is then done when you come to do your mapping. 
    // You can create a map whenever you want, but this will slow your code down as the mapping creation involves reflection.

    Mapper.Initialize(config =>
    {
        config.ConstructServicesUsing(container.GetInstance);
        config.AddProfile(new WebApiAutomapperProfile());
        config.AddGlobalIgnore("Errors");
        config.AddGlobalIgnore("IsModelValid");
        config.AddGlobalIgnore("BaseValidator");
        config.AddGlobalIgnore("AuditInformation");
     });

     container.RegisterSingleton<IMappingEngine>(Mapper.Engine);

     Mapper.AssertConfigurationIsValid();

     container.RegisterWebApiControllers(GlobalConfiguration.Configuration);

     container.Verify();
}

然后每个Controller在构造函数中接收一个IMappingEngine并使用:

MappingEngine.Map<>

模型类示例

public class EntityModel : BaseModel.BaseModel<EntityModel >
{
    public EntityModel(IMappingEngine mappingEngine) : base(mappingEngine)
    {
    }
}

基础模型

public abstract class BaseModel<T> : IBaseModel
        where T : class
{
    public IMappingEngine MappingEngine { get; set; }

    protected BaseModel(IMappingEngine mappingEngine)
    {
        this.MappingEngine = mappingEngine;
    }
}

错误信息说:

Type needs to have a constructor with 0 args or only optional args\r\nParameter name: type

Mapping types:
Entity -> EntityModel
Model.Entity -> WebApi.Models.EntityModel

Destination path:
EntityModel

Source value:
System.Data.Entity.DynamicProxies.Entity_1D417730D5BE3DEAF6292D57AB49B32FA18136A1DCF74193E8716EC6EE4DC62B

问题是 IMappingEngine mappingEngine 没有被注入到模型的构造函数中。问题是如何让它发挥作用。

当我尝试做 .Map 时抛出错误

return this.MappingEngine.Map<Entity,EntityModel>(this.EntityRepository.AllMaterialized().FirstOrDefault());

这就是 Stacktrace

   at WebApi.Controllers.Api.EntityController.Get() in c:\Users\Guillermo\Downloads\Backend\WebApi\Controllers\Api\EntityController.cs:line 108
   at lambda_method(Closure , Object , Object[] )
   at System.Web.Http.Controllers.ReflectedHttpActionDescriptor.ActionExecutor.<>c__DisplayClass10.<GetExecutor>b__9(Object instance, Object[] methodParameters)
   at System.Web.Http.Controllers.ReflectedHttpActionDescriptor.ActionExecutor.Execute(Object instance, Object[] arguments)
   at System.Web.Http.Controllers.ReflectedHttpActionDescriptor.ExecuteAsync(HttpControllerContext controllerContext, IDictionary`2 arguments, CancellationToken cancellationToken)

有什么遗漏或错误吗?

提前致谢!吉列尔莫。

【问题讨论】:

  • 嗨吉列尔莫。很可能您的问题仅与 Automapper 和 SimpleInjector 相关,WebApi 就在旁边。您必须尝试以下方法以轻松帮助您: 1. 准备一个单元测试来演示问题。 2. 尝试替换 Automapper(例如,使用 Value Injecter valueinjecter.codeplex.com 来确定是否是映射问题)。 3. 尝试替换 SimpleInjector(例如用 Windsor)。这可能会在你的黑暗中提供一些光明。
  • 你有什么例外吗?如果是这样,请发布带有内部异常和堆栈跟踪的完整异常。
  • 嗨@Apocatastasis,更改 IoC 容器对我来说不是一种选择,因为我正在为已经使用它的更大的“插件系统”做一个“插件系统”。我知道这是一个映射问题。问题是 IMappingEngine mappingEngine 没有被注入到模型的构造函数中。问题是如何让它发挥作用。为上述问题添加了错误描述。
  • @Steven 错误信息是这样的:Type need to have a constructor with 0 args or only optional args\r\nParameter name: type 问题是 IMappingEngine mappingEngine 没有被注入到模型的构造函数中.这就是为什么消息这么说的原因,带参数的模型只有一个构造函数。为上述问题添加了错误描述。
  • 您误解了@Apocatastasis 评论。他并没有建议您远离 Simple Injector,他只是建议您通过设计和征服来​​确定问题所在。构建一个最小的可重现示例。如果您在该设置中切换容器,并且问题消失了,您就知道问题出在 DI 配置中。

标签: c# asp.net-web-api asp.net-web-api2 automapper simple-injector


【解决方案1】:

由于您的EntityController 被简单注入器正确解析,并且它依赖于IMapperEngine,因此您可以放心,映射器引擎已正确注入。可能发生的情况是注册的Mapper.Engine 那时没有正确初始化,但我只是在猜测。 Automapper 专家应该能够看到这里出了什么问题。

但是,您的问题的核心是您尝试将依赖项注入到域实体中。看看this article from Jimmy Bogard(Automapper 的创建者),他解释了为什么这是一个坏主意。

一旦在实体初始化期间不再需要服务依赖项,这个问题就会完全消失。

【讨论】:

  • hmm...这些是 Dto 类,不是域类,不确定是否相同...无论如何都会阅读该文章...thx
  • @polonskyg:对于 DTO 来说也是如此,但我想说这个论点更有说服力。虽然实体可以使用服务(在应用领域驱动设计时),但 DTO 根本不应该包含任何逻辑(出于某种原因,它们被称为 Data 传输对象),所以向它们注入依赖项是一个真正的大禁忌。
  • 我又想了想,我认为你是对的,为什么要在被映射的内容中使用 IMappingEngine?现在,Controller 将负责将 Entities 转换为 Dtos 并接收 IMappingEngine。谢谢!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-10-08
  • 2013-06-17
相关资源
最近更新 更多