c# - 具有范围依赖关系的 ASP.NET CORE Automapper 配置文件
问题描述
在我的用例中,我需要根据上下文映射一个属性。请记住,我通过调用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; }
}
基本上,目的地应该包含自己的评论数量。当前用户是使用ICurrentUserService
带有属性的动态解析的UserId
。
我已经通过以下方式解决了这个问题:
在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 周期。
有没有更优雅的方法,比如将映射配置文件创建为单例,然后在作用域/瞬态映射器中执行它?
解决方案
我将回答我自己的问题以供将来参考:
感谢@lucian-bargaoanu 在评论中提供链接: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);
}
}
推荐阅读
- python - 在heroku上安装pdftotext库
- c# - 有没有办法避免使用 interop.word 出现分页符的空白页?
- postgresql - 是否可以在零停机时间的情况下将 postgres 9.6 升级到 10。可以遵循哪些方法?
- python - 使用 pandas 在 Excel 编写器输出中仅显示过滤的行
- excel - 如何在一系列行和列中循环计数
- c++ - 如何在 QGrapicsScene 中用新图像替换以前的图像
- mongodb - 如何将字符串转换为整数 [Laravel - MongoDB]
- php - Wordpress functions.php 中的多个 Access-Control-Allow-Origin CORS 标头
- javascript - 如何使用 ajax 调用获取 Microsoft Graph API 访问令牌
- c# - 基于节点名称拆分大型 JSON 的通用代码