.NET 6开发TodoList应用之使用AutoMapper实现GET请求

2022-04-16 11:37:45
目录
需求目标原理与思路实现引入AutoMapperionToken); }}

最后实现Controller层的逻辑:

TodoListController.cs

// 省略其他...[HttpGet]public async Task<ActionResult<List<TodoListBriefDto>>> Get(){    return await _mediator.Send(new GetTodosQuery());}

GET Single TodoList

首先在Application/TodoItems/Queries/下新建目录GetTodoItems用于存放获取TodoItem相关的所有逻辑:

定义TodoItemDtoTodoListDto对象:

TodoItemDto.cs

using AutoMapper;using TodoList.Application.Common.Mappings;using TodoList.Domain.Entities;namespace TodoList.Application.TodoItems.Queries.GetTodoItems;// 实现IMapFrom<T>接口public class TodoItemDto : IMapFrom<TodoItem>{    public Guid Id { get; set; }    public Guid ListId { get; set; }    public string? Title { get; set; }    public bool Done { get; set; }    public int Priority { get; set; }    // 实现接口定义的Mapping方法,并提供除了Convention之外的特殊字段的转换规则    public void Mapping(Profile profile)    {        profile.CreateMap<TodoItem, TodoItemDto>()            .ForMember(d => d.Priority, opt => opt.MapFrom(s => (int)s.Priority));    }}

TodoListDto.cs

using TodoList.Application.Common.Mappings;using TodoList.Application.TodoItems.Queries.GetTodoItems;namespace TodoList.Application.TodoLists.Queries.GetSingleTodo;// 实现IMapFrom<T>接口,因为此Dto不涉及特殊字段的Mapping规则// 并且属性名称与领域实体保持一致,根据Convention规则默认可以完成Mapping,不需要额外实现public class TodoListDto : IMapFrom<Domain.Entities.TodoList>{    public Guid Id { get; set; }    public string? Title { get; set; }    public string? Colour { get; set; }    public IList<TodoItemDto> Items { get; set; } = new List<TodoItemDto>();}

创建一个根据ListId来获取包含TodoItems子项的spec:

TodoListSpec.cs

using Microsoft.EntityFrameworkCore;using TodoList.Application.Common;namespace TodoList.Application.TodoLists.Specs;public sealed class TodoListSpec : SpecificationBase<Domain.Entities.TodoList>{    public TodoListSpec(Guid id, bool includeItems = false) : base(t => t.Id == id)    {        if (includeItems)        {            AddInclude(t => t.Include(i => i.Items));        }    }}

我们仍然为这个查询新建一个GetSingleTodo目录,并实现GetSIngleTodoQuery

GetSingleTodoQuery.cs

using AutoMapper;using AutoMapper.QueryableExtensions;using MediatR;using Microsoft.EntityFrameworkCore;using TodoList.Application.Common.Interfaces;using TodoList.Application.TodoLists.Specs;namespace TodoList.Application.TodoLists.Queries.GetSingleTodo;public MhgqbBsQclass GetSingleTodoQuery : IRequest<TodoListDto?>{    public Guid ListId { get; set; }}public class ExportTodosQueryHandler : IRequestHandler<GetSingleTodoQuery, TodoListDto?>{    private readonly IRepository<Domain.Entities.TodoList> _repository;    private readonly IMapper _mapper;    public ExportTodosQueryHandler(IRepository<Domain.Entities.TodoList> repository, IMapper mapper)    {        _repository = repository;        _mapper = mapper;    }    public async Task<TodoListDto?> Handle(GetSingleTodoQuery request, CancellationToken cancellationToken)    {        var spec = new TodoListSpec(request.ListId, true);        return await _repository            .GetAsQueryable(spec)            .AsNoTracking()            .ProjectTo<TodoListDto>(_mapper.ConfigurationProvider)            .FirstOrDefaultAsync(cancellationToken);    }}

添加Controller逻辑,这里的Name是为了完成之前遗留的201返回的问题,后文会有使用。

TodoListController.cs

// 省略其他...[HttpGet("{id:Guid}", Name = "TodListById")]public async Task<ActionResult<TodoListDto>> GetSingleTodoList(Guid id){    return await _mediator.Send(new GetSingleTodoQuery    {        ListId = id    }) ?? throw new InvalidOperationException();}

验证

运行Api项目

获取所有TodoList列表

请求

.NET 6开发TodoList应用之使用AutoMapper实现GET请求

响应

.NET 6开发TodoList应用之使用AutoMapper实现GET请求

获取单个TodoList详情

请求

.NET 6开发TodoList应用之使用AutoMapper实现GET请求

响应

.NET 6开发TodoList应用之使用AutoMapper实现GET请求

填一个POST文章里的坑

在使用.NET 6开发TodoList应用(6)——使用MediatR实现POST请求中我们留了一个问题,即创建TodoList后的返回值当时我们是临时使用Id返回的,推荐的做法是下面这样:

// 省略其他...[HttpPost]public async Task<IActionResult> Create([FromBody] CreateTodoListCommand command){    var createdTodoList = await _mediator.Send(command);    // 创建成功返回201    return CreatedAtRoute("TodListById", new { id = createdTodoList.Id }, createdTodoList);}

请求

.NET 6开发TodoList应用之使用AutoMapper实现GET请求

返回

Content部分

.NET 6开发TodoList应用之使用AutoMapper实现GET请求

以及Header部分

.NET 6开发TodoList应用之使用AutoMapper实现GET请求

我们主要观察返回的HTTPStatusCode是201,并且在Header中location字段表明了创建资源的位置。

总结

其他和查询请求相关的例子我就不多举了,通过两个简单的例子想说明如何组织CQRS模式下的代码逻辑。我们可以直观地看出,CQRS操作是通过IRequest和IRequestHandler实现的,其中IRequest部分直接和API接口的请求参数直接或间接相关联,将请求参数通过注入的_mediator对象进行处理。

同时我们在实现两个查询接口的过程中也可以发现,查询语句中的Select部分现在已经被AutoMapper的相关功能替代掉了,所以在调用Repository时,可能并不经常用到SelectXXXX相关的具有数据类型转换的接口,更多的还是使用返回IQueryable对象的接口。这和我在使用.NET 6开发TodoList应用之实现Repository模式中实践的有一点出入,在那篇文章中,我之所以把Repository的抽象层次做的很高的原因是,我希望顺便把类似的类库实现思路也梳理一下。就像评论中有朋友提出的那样,其实更多的场合下,因为会配合系统里其他组件的使用,比如这里的AutoMapper,那么对于Repository的实际需求就变成了只需要给我一个IQueryable对象即可。这也是我在那篇文章中试图强调的那样:关于Repository,每个人的理解和实现都有差别,因为取决于抽象程度和应用场合。

这一篇文章处理了关于GET的请求,有一个小的知识点没有讲到:后台分页返回,这部分内容会在后面专门再回到查询的场景里来说。然后又留了一个小坑下一篇文章来说:全局异常处理和统一返回类型。

以上就是.NET 6开发TodoList应用之使用AutoMapper实现GET请求的详细内容,更多关于.NET 6 AutoMapper实现GET请求的资料请关注我们其它相关文章!