【问题标题】:AutoMapper: dependency injection with DTOsAutoMapper:使用 DTO 进行依赖注入
【发布时间】:2023-09-08 11:40:02
【问题描述】:

我正在尝试将域模型映射到 DTO

我的领域模型是:

public class Vendor
{
    public Guid Id { get; set; }
    public string FullName { get; set; }

    public string Email { get; set; }
    public string Mobile { get; set; }
    public Guid RegionId { get; set; }
    public string CompanyName { get; set; }
    public string Website { get; set; }
    public string OfficalEmail { get; set; }
    public string OfficeNumber { get; set; }
    public virtual Region Regions { get; set; }
    public string AlternateNumber { get; set; }
    public string Address { get; set; }
    public string ImageName { get; set; }

    [NotMapped] public IFormFile ImageFile { get; set; }
}

我的 DTO 是:

public class GetVendorsDto
{
    private readonly IHttpContextAccessor _httpContextAccessor;

    public GetVendorsDto(IHttpContextAccessor httpContextAccessor)
    {
        _httpContextAccessor = httpContextAccessor;
    }

    public Guid Id { get; set; }
    public string FullName { get; set; }
    public string Email { get; set; }
    public string Mobile { get; set; }
    public Guid RegionId { get; set; }
    public virtual RegionDto Regions { get; set; }
    public string CompanyName { get; set; }
    public string Website { get; set; }
    public string OfficalEmail { get; set; }
    public string OfficeNumber { get; set; }
    public string AlternateNumber { get; set; }
    public string Address { get; set; }

    public string ImageName { get; set; }

    public string ImageSrc
    {
        get { return ImageSrc; }
        set
        {
            ImageSrc =
                $"{_httpContextAccessor.HttpContext.Request.Scheme}://{_httpContextAccessor.HttpContext.Request.Host.Value}/Images/{this.ImageName}";
        }
    }
}

在 DTO 中,我试图在 ImageSrc 属性中构造图像 URL,但出现此错误:

我已将HttpContextAccessor 添加到Startup

services.AddScoped<HttpContextAccessor>();

但我仍然收到错误 $Type needs to have a constructor with 0 args or only optional args.

AutoMapper.AutoMapperMappingException: Error mapping types.

    Mapping types:
    Object -> List`1
    System.Object -> System.Collections.Generic.List`1[[Application.Vendors.Dtos.GetVendorsDto, Application, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]]
     ---> System.ArgumentException: Application.Vendors.Dtos.GetVendorsDto needs to have a constructor with 0 args or only optional args. (Parameter 'type')
       at lambda_method110(Closure , Object , List`1 , ResolutionContext )
       --- End of inner exception stack trace ---
       at lambda_method110(Closure , Object , List`1 , ResolutionContext )
       at Application.Vendors.List.Handler.Handle(Query request, CancellationToken cancellationToken) in D:\Project_20-21\ProjectManagement\Application\Vendors\List.cs:line 38
       at MediatR.Pipeline.RequestExceptionProcessorBehavior`2.Handle(TRequest request, CancellationToken cancellationToken, RequestHandlerDelegate`1 next)
       at MediatR.Pipeline.RequestExceptionProcessorBehavior`2.Handle(TRequest request, CancellationToken cancellationToken, RequestHandlerDelegate`1 next)
       at MediatR.Pipeline.RequestExceptionActionProcessorBehavior`2.Handle(TRequest request, CancellationToken cancellationToken, RequestHandlerDelegate`1 next)
       at MediatR.Pipeline.RequestExceptionActionProcessorBehavior`2.Handle(TRequest request, CancellationToken cancellationToken, RequestHandlerDelegate`1 next)
       at MediatR.Pipeline.RequestPostProcessorBehavior`2.Handle(TRequest request, CancellationToken cancellationToken, RequestHandlerDelegate`1 next)
       at MediatR.Pipeline.RequestPreProcessorBehavior`2.Handle(TRequest request, CancellationToken cancellationToken, RequestHandlerDelegate`1 next)
       at API.Controllers.VendorsController.GetVendors() in D:\Project_20-21\ProjectManagement\API\Controllers\VendorsController.cs:line 23
       at lambda_method13(Closure , Object )

【问题讨论】:

  • 您是否考虑过将您的类设计为在属性中不需要 IHttpContextAccessor?

标签: asp.net-core asp.net-core-mvc asp.net-core-webapi


【解决方案1】:

您不能对 DTO 使用依赖注入(或者您不想:让您的 DTO 保持简单和愚蠢)。但是 AutoMapper 允许您定义 可以 使用依赖注入的自定义转换器。您需要在映射配置中实现IValueConverter&lt;TSourceMember, TDestMember&gt; 设置。

CreateMap<Vendor, VendorDto>().ForMember(
    dto => dto.ImagePath,
    opts => opts.ConvertUsing<ImagePathConverter, string>()
);

这是一个工作示例:

public record Vendor
{
    public string Name { get; init; }
    public string ImagePath { get; init; }
}

public record VendorDto
{

    public string Name { get; init; }
    public string ImagePath { get; init; }
}

internal class MapperConfig : Profile
{
    public MapperConfig()
    {
        CreateMap<Vendor, VendorDto>().ForMember(
            dto => dto.ImagePath,
            opts => opts.ConvertUsing<ImagePathConverter, string>()
        );
    }

    private class ImagePathConverter : IValueConverter<string, string>
    {
        private IHttpContextAccessor _contextAccessor;

        public ImagePathConverter(IHttpContextAccessor contextAccessor)
        {
            _contextAccessor = contextAccessor;
        }

        public string Convert(string sourceMember, ResolutionContext context)
        {
            return sourceMember + _contextAccessor.HttpContext!.Request.Path.ToString();
        }
    }
}

供参考:

https://docs.automapper.org/en/stable/Value-converters.html

【讨论】:

    最近更新 更多