项目
版本

AutoMapper 在映射前后执行操作

有时,您可能需要在映射前后执行自定义逻辑。这种情况应尽量避免,因为通常更倾向于在 AutoMapper 外部完成这部分工作。不过,您可以创建全局的映射前后动作:

var configuration = new MapperConfiguration(cfg => {
  cfg.CreateMap<Source, Dest>()
    .BeforeMap((src, dest) => src.Value = src.Value + 10) // 映射前,源对象的Value值加10
    .AfterMap((src, dest) => dest.Name = "John"); // 映射后,目标对象的Name设为"John"
});

或者,在执行映射时可以创建映射前后回调:

int i = 10;
mapper.Map<Source, Dest>(src, opt => {
    opt.BeforeMap((src, dest) => src.Value = src.Value + i); // 根据外部变量i调整源对象的Value
    opt.AfterMap((src, dest) => dest.Name = HttpContext.Current.Identity.Name); // 使用HttpContext设置目标对象的Name
});

后者的配置方式在需要将上下文信息传递给映射前后动作时特别有用。

使用 IMappingAction

您可以将映射前后动作封装进小而可重用的类中。这些类需要实现 IMappingAction<in TSource, in TDestination> 接口。

沿用之前的例子,下面是如何将对象命名为 "John" 的封装示例:

public class NameMeJohnAction : IMappingAction<SomePersonObject, SomeOtherPersonObject>
{
    public void Process(SomePersonObject source, SomeOtherPersonObject destination, ResolutionContext context)
    {
        destination.Name = "John"; // 将目标对象的Name设为"John"
    }
}

var configuration = new MapperConfiguration(cfg => {
  cfg.CreateMap<SomePersonObject, SomeOtherPersonObject>()
    .AfterMap<NameMeJohnAction>(); // 映射后应用此动作
});

依赖注入

虽然无法直接在 Profile 类中注入依赖,但可以在 IMappingAction 实现中进行依赖注入。

以下示例展示了如何将访问当前 HttpContextIMappingActionProfile 的后映射动作连接起来,利用依赖注入:

public class SetTraceIdentifierAction : IMappingAction<SomeModel, SomeOtherModel>
{
    private readonly IHttpContextAccessor _httpContextAccessor;

    public SetTraceIdentifierAction(IHttpContextAccessor httpContextAccessor)
    {
        _httpContextAccessor = httpContextAccessor ?? throw new ArgumentNullException(nameof(httpContextAccessor));
    }

    public void Process(SomeModel source, SomeOtherModel destination, ResolutionContext context)
    {
        destination.TraceIdentifier = _httpContextAccessor.HttpContext.TraceIdentifier; // 设置目标对象的TraceIdentifier
    }
}

public class SomeProfile : Profile
{
    public SomeProfile()
    {
        CreateMap<SomeModel, SomeOtherModel>()
            .AfterMap<SetTraceIdentifierAction>(); // 映射后应用此动作
    }
}

通过以下方式将所有部分连接在一起:

public class Startup
{
    public void ConfigureServices(IServiceCollection services)
    {
        services.AddAutoMapper(typeof(Startup).Assembly); // 配置AutoMapper并注册依赖
    }
    // 其他配置...
}
在本文档中