.Net Core 3.1 上的 AutoMapper

C1X*_*C1X 3 c# automapper asp.net-core asp.net-core-3.1

在 Net Core 3.1 应用程序中,我尝试使用 AutoMapper.Extensions.Microsoft.DependencyInjection 7。在解决方案中,我有 3 个项目:

  • 内容(启动项目)
  • 实体框架

nuget安装后,这是我的代码:

内容项目中的 Startup.cs:

using AutoMapper;
using Project.Content.EntityFrameWork;
using Project.Content.Dto;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;

namespace Project.Content
{
    public class Startup
    {
        public Startup(IConfiguration configuration)
        {
            Configuration = configuration;
        }

        public IConfiguration Configuration { get; }

        // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddControllers();
            // Auto Mapper Configurations
            services.AddAutoMapper(typeof(AutoMapping));

            string connectionString = Configuration["ConnectionString:Default"];
            services.AddDbContext<ProjectContext>(options =>
        options.UseSqlServer(connectionString));
        }

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }

            app.UseHttpsRedirection();

            app.UseRouting();

            app.UseAuthorization();

            app.UseEndpoints(endpoints =>
            {
                endpoints.MapControllers();
            });
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

内容项目中的 AutoMapping.cs:

using AutoMapper;
using Project.Content.Core.Domain.Model;

namespace Project.Content.Dto
{
    class AutoMapping : Profile
    {
        public AutoMapping()
        {
            CreateMap<Exercise, ExerciseDto>();
            CreateMap<ExerciseDto, Exercise>();
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

这是我试图映射的控制器:

using AutoMapper;
using Project.Content.EntityFrameWork;
using Project.Content.Dto;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.Linq;

namespace Project.Content.Controllers
{
    [ApiController]
    [Route("/exercise")]
    public class ExercisesController : ControllerBase
    {
        private readonly ILogger<ExercisesController> _logger;
        private ProjectContext _dbContext;
        private IMapper _mapper;

        public ExercisesController(ILogger<ExercisesController> logger, ProjectContext dbContext, IMapper mapper)
        {
            _logger = logger;
            _dbContext = dbContext;
            _mapper = mapper;
        }

        [HttpGet("{id}")]
        public ExerciseDto GetById(int id)
        {

            var exercise =  _mapper.Map<ExerciseDto>(_dbContext.Exercises.Where(x => x.Id == id));
            return exercise;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

在此控制器中,当它尝试映射对象时会显示错误:

AutoMapper.AutoMapperMappingException:缺少类型映射配置或不受支持的映射。

映射类型:EntityQueryable1 -> ExerciseDto Microsoft.EntityFrameworkCore.Query.Internal.EntityQueryable1[[Project.Content.Core.Domain.Model.Exercise, Project.Content.Core, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]] -> Project.Content.Dto.ExerciseDto at lambda_method(Closure , EntityQueryable`1 , ExerciseDto , ResolutionContext ) at lambda_method(Closure , Object , Object , ResolutionContext ) at Project.Content.Controllers.ExercisesController.GetById(Int32 id) in C:\Projects\Project\Project.Content\Project.Content.Service \Controllers\ExercisesController.cs:line 44 at lambda_method(Closure , Object , Object[] ) at Microsoft.Extensions.Internal.ObjectMethodExecutor.Execute(Object target, Object[] parameters) at Microsoft.AspNetCore.Mvc.Infrastructure.ActionMethodExecutor。 SyncObjectResultExecutor.Execute(IActionResultTypeMapper mapper, ObjectMethodExecutor executor, Object controller,Object[] arguments) at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.InvokeActionMethodAsync() at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted) at Microsoft.AspNetCore.Mvc .Infrastructure.ControllerActionInvoker.InvokeNextActionFilterAsync() --- 从上一个抛出异常的位置开始的堆栈跟踪结束 --- 在 Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Rethrow(ActionExecutedContextSealed context) 在 Microsoft.AspNetCore.Mvc.Infrastructure。 ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted) 在 Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker。InvokeInnerFilterAsync() --- 从上一个抛出异常的位置开始的堆栈跟踪结束 --- 在 Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.g__Awaited|19_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted) at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.g__Logged|17_1(ResourceInvoker invoker) at Microsoft.AspNetCore.Routing.EndpointMiddleware.g__AwaitRequestTask|6_0(Endpoint endpoint, Task requestTask, ILogger logger) at Microsoft.AspNetCore.Author Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext context) 处的 AuthorizationMiddleware.Invoke(HttpContext context)g__Awaited|19_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted) at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.g__Logged|17_1(ResourceInvoker invoker) at Microsoft.AspNetCore.Routing.EndpointMiddleTaskAg |6_0(Endpoint endpoint, Task requestTask, ILogger logger) at Microsoft.AspNetCore.Authorization.AuthorizationMiddleware.Invoke(HttpContext context) at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext context)g__Awaited|19_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted) at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.g__Logged|17_1(ResourceInvoker invoker) at Microsoft.AspNetCore.Routing.EndpointMiddleTaskAg |6_0(Endpoint endpoint, Task requestTask, ILogger logger) at Microsoft.AspNetCore.Authorization.AuthorizationMiddleware.Invoke(HttpContext context) at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext context)g__AwaitRequestTask|6_0(Endpoint endpoint, Task requestTask, ILogger logger) at Microsoft.AspNetCore.Authorization.AuthorizationMiddleware.Invoke(HttpContext context) at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext context)g__AwaitRequestTask|6_0(Endpoint endpoint, Task requestTask, ILogger logger) at Microsoft.AspNetCore.Authorization.AuthorizationMiddleware.Invoke(HttpContext context) at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext context)

Tyl*_*ley 5

您正在尝试映射IQueryable<T>,因为它使用延迟执行。您需要使用类似ToList()ToListAsync()在尝试映射它之前执行查询。

您还尝试将集合映射到单个项目。您应该改为映射到集合。最终结果看起来像这样

[HttpGet("{id}")]
public ExerciseDto GetById(int id)
{
  var exercises =  _dbContext.Exercises.Where(x => x.Id == id).ToList();
  return _mapper.Map<IEnumerable<ExerciseDto>>(exercises);
}
Run Code Online (Sandbox Code Playgroud)

或者,您可以利用 AutoMappers 可查询扩展来执行投影,这可能会导致更好的 SQL 性能,因为它将尝试仅查询必要的数据。这可能看起来像这样

[HttpGet("{id}")]
public ExerciseDto GetById(int id)
{
  return _mapper.ProjectTo<ExerciseDto>(_dbContext.Exercises.Where(x => x.Id == id)).ToList();
}
Run Code Online (Sandbox Code Playgroud)

附带说明一下,如果您打算将此查询作为单个对象,或者如果它不存在则找不到,您可以使用FirstOrDefault代替Where. 此外,您可以返回 IActionResult 以利用基本控制器结果,例如NotFoundOk