【问题标题】:ASP.NET CORE Automapper Profile with Scoped Dependency具有范围依赖关系的 ASP.NET CORE Automapper 配置文件
【发布时间】:2021-08-01 04:54:56
【问题描述】:

在我的用例中,我需要根据上下文映射属性。 请记住,我通过调用 ProjectTo 函数将 Automapper 与实体框架一起使用。所以遗憾的是,自定义值解析器是没有选择的。

简单示例:

public class Comment 
{
  public int Id { get;set; }
  public int UserId { get;set; }
  ...
}

public class Source 
{
  public int Id { get; set; }
  public IEnumerable<Comment> Comments  { get; set; }
}

public class Destination 
{
  public int Id { get; set; }
  public int NumOwnComments { get; set; }
}

基本上,Destination 应该包含自己的 cmets 的数量。 当前用户是使用带有属性UserIdICurrentUserService 动态解析的。

我已经通过以下方式解决了这个问题:

Startup.cs 中我添加了Transient 映射器/配置。

  services.AddTransient(provider => new MapperConfiguration(cfg => { cfg.AddProfile(new MappingProfile(provider.GetService<ICurrentUserService>())); })
        .CreateMapper());

然后我在 MappingProfile 中按以下方式创建了映射:

public class MappingProfile : Profile {

    public MappingProfile(ICurrentUserService currentUserService) {
        CreateMap<Source, Destination>()
            .ForMember(vm => vm.NumOwnComments, opts => opts.MapFrom(s => s.Comments.Count(c => c.UserId == currentUserService.UserId))
        ;
    }
}

虽然这可行,但将映射器配置作为瞬态/作用域依赖项并不是很好。每个请求都会创建这个映射器,这会消耗大量内存和 CPU 周期。

有没有更优雅的方法,比如将映射配置文件创建为单例,然后在作用域/瞬态映射器中执行它?

【问题讨论】:

  • 哇,我怎么会错过……谢谢,我会试试的。您对如何在整个项目中管理参数有什么建议吗?自定义 ProjectTo 扩展方法,例如 ProjectToDestinationDto(currentUser)?
  • 应该可以。试一试:)
  • 非常感谢它运行良好并解决了我的性能问题!

标签: c# asp.net-core dependency-injection entity-framework-core automapper


【解决方案1】:

我会回答我自己的问题以供将来参考:

感谢 @lucian-bargaoanu 在 cmets 中提供链接:https://docs.automapper.org/en/latest/Queryable-Extensions.html#parameterization

动态参数可以通过 ProjectTo 方法传递。

我最终为我的所有 DTO 投影创建了扩展方法

public static class DestinationProjection 
{
    public static IQueryable<Destination> ProjectToDestination(IQueryable source, IConfiguration configuration, int currentUserId) {
        return source.ProjectTo<Destination>(configuration, new { currentUserId });
    }
}

在映射中我使用了这个参数

public class MappingProfile : Profile 
{
    public MappingProfile() {
        int? currentUserId = null;
        CreateMap<Source, Destination>()
            .ForMember(vm => vm.NumOwnComments, opts => opts.MapFrom(s => s.Comments.Count(c => c.UserId == currentUserId.GetValueOrDefault()))
        ;
    }
}

这样我可以在处理程序类中注入我的ICurrentUserService

public class DestinationListQueryHandler  
{
    public DestinationListQueryHandler(IMapper mapper, IDbContext dbContext, ICurrentUserService currentUserService) 
    {
         // field initialization logic
    }

    public async Task<IEnumerable<Destination>> Handle(CancellationToken cancellationToken)
    {
        return await dbContext.Sources.ProjectToDestination(mapper.ConfigurationProvider, currentUserId).ToListAsync(cancellationToken);
    }
}

【讨论】:

    猜你喜欢
    • 2018-06-07
    • 2019-08-12
    • 2021-08-25
    • 1970-01-01
    • 2023-03-12
    • 2018-12-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多