如何使用AutoMapper实现GET请求(automapper,get,开发技术)

时间:2024-05-09 03:02:23 作者 : 石家庄SEO 分类 : 开发技术
  • TAG :

    需求

    需求很简单:实现GET请求获取业务数据。在这个阶段我们经常使用的类库是AutoMapper。

    目标

    合理组织并使用AutoMapper,完成GET请求。

    原理与思路

    首先来简单地介绍一下这这个类库。

    关于AutoMapper

    在业务侧代码和数据库实体打交道的过程中,一个必不可少的部分就是返回的数据类型转换。对于不同的请求来说,希望得到的返回值是数据库实体的一部分/组合/计算等情形。我们就经常需要手写用于数据对象转换的代码,但是转换前后可能大部分情况下有着相同名称的字段或属性。这部分工作能避免手写冗长的代码吗?可以。

    我们希望接受的请求和返回的值(统一称为model)具有以下两点需要遵循的原则:

    1.每个model被且只被一个API消费;

    2.每个model里仅仅包含API发起方希望包含的必要字段或属性。

    AutoMapper库就是为了实现这个需求而存在的,它的具体用法请参考官方文档,尤其是关于Convention的部分,避免重复劳动。

    实现

    所有需要使用AutoMapper的地方都集中在Application项目中。

    引入AutoMapper

    $dotnetaddsrc/TodoList.Application/TodoList.Application.csprojpackageAutoMapper.Extensions.Microsoft.DependencyInjection

    然后在Application/Common/Mappings下添加配置,提供接口的原因是我们后面就可以在DTO里实现各自对应的Mapping规则,方便查找。

    IMapFrom.cs

    usingAutoMapper;namespaceTodoList.Application.Common.Mappings;publicinterfaceIMapFrom<T>{voidMapping(Profileprofile)=>profile.CreateMap(typeof(T),GetType());}

    MappingProfile.cs

    usingSystem.Reflection;usingAutoMapper;namespaceTodoList.Application.Common.Mappings;publicclassMappingProfile:Profile{publicMappingProfile()=>ApplyMappingsFromAssembly(Assembly.GetExecutingAssembly());privatevoidApplyMappingsFromAssembly(Assemblyassembly){vartypes=assembly.GetExportedTypes().Where(t=>t.GetInterfaces().Any(i=>i.IsGenericType&&i.GetGenericTypeDefinition()==typeof(IMapFrom<>))).ToList();foreach(vartypeintypes){varinstance=Activator.CreateInstance(type);varmethodInfo=type.GetMethod("Mapping")??type.GetInterface("IMapFrom`1")!.GetMethod("Mapping");methodInfo?.Invoke(instance,newobject[]{this});}}}

    DependencyInjection.cs进行依赖注入:

    DependencyInjection.cs

    //省略其他...services.AddAutoMapper(Assembly.GetExecutingAssembly());services.AddMediatR(Assembly.GetExecutingAssembly());returnservices;

    实现GET请求

    在本章中我们只实现TodoListQuery接口(GET),并且在结果中包含TodoItem集合,剩下的接口后面的文章中逐步涉及。

    GET All TodoLists

    Application/TodoLists/Queries/下新建一个目录GetTodos用于存放创建一个TodoList相关的所有逻辑:

    定义TodoListBriefDto对象:

    TodoListBriefDto.cs

    usingTodoList.Application.Common.Mappings;namespaceTodoList.Application.TodoLists.Queries.GetTodos;//实现IMapFrom<T>接口,因为此Dto不涉及特殊字段的Mapping规则//并且属性名称与领域实体保持一致,根据Convention规则默认可以完成Mapping,不需要额外实现publicclassTodoListBriefDto:IMapFrom<Domain.Entities.TodoList>{publicGuidId{get;set;}publicstring?Title{get;set;}publicstring?Colour{get;set;}}

    GetTodosQuery.cs

    usingAutoMapper;usingAutoMapper.QueryableExtensions;usingMediatR;usingMicrosoft.EntityFrameworkCore;usingTodoList.Application.Common.Interfaces;namespaceTodoList.Application.TodoLists.Queries.GetTodos;publicclassGetTodosQuery:IRequest<List<TodoListBriefDto>>{}publicclassGetTodosQueryHandler:IRequestHandler<GetTodosQuery,List<TodoListBriefDto>>{privatereadonlyIRepository<Domain.Entities.TodoList>_repository;privatereadonlyIMapper_mapper;publicGetTodosQueryHandler(IRepository<Domain.Entities.TodoList>repository,IMappermapper){_repository=repository;_mapper=mapper;}publicasyncTask<List<TodoListBriefDto>>Handle(GetTodosQueryrequest,CancellationTokencancellationToken){returnawait_repository.GetAsQueryable().AsNoTracking().ProjectTo<TodoListBriefDto>(_mapper.ConfigurationProvider).OrderBy(t=>t.Title).ToListAsync(cancellationToken);}}

    最后实现Controller层的逻辑:

    TodoListController.cs

    //省略其他...[HttpGet]publicasyncTask<ActionResult<List<TodoListBriefDto>>>Get(){returnawait_mediator.Send(newGetTodosQuery());}

    GET Single TodoList

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

    定义TodoItemDtoTodoListDto对象:

    TodoItemDto.cs

    usingAutoMapper;usingTodoList.Application.Common.Mappings;usingTodoList.Domain.Entities;namespaceTodoList.Application.TodoItems.Queries.GetTodoItems;//实现IMapFrom<T>接口publicclassTodoItemDto:IMapFrom<TodoItem>{publicGuidId{get;set;}publicGuidListId{get;set;}publicstring?Title{get;set;}publicboolDone{get;set;}publicintPriority{get;set;}//实现接口定义的Mapping方法,并提供除了Convention之外的特殊字段的转换规则publicvoidMapping(Profileprofile){profile.CreateMap<TodoItem,TodoItemDto>().ForMember(d=>d.Priority,opt=>opt.MapFrom(s=>(int)s.Priority));}}

    TodoListDto.cs

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

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

    TodoListSpec.cs

    usingMicrosoft.EntityFrameworkCore;usingTodoList.Application.Common;namespaceTodoList.Application.TodoLists.Specs;publicsealedclassTodoListSpec:SpecificationBase<Domain.Entities.TodoList>{publicTodoListSpec(Guidid,boolincludeItems=false):base(t=>t.Id==id){if(includeItems){AddInclude(t=>t.Include(i=>i.Items));}}}

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

    GetSingleTodoQuery.cs

    usingAutoMapper;usingAutoMapper.QueryableExtensions;usingMediatR;usingMicrosoft.EntityFrameworkCore;usingTodoList.Application.Common.Interfaces;usingTodoList.Application.TodoLists.Specs;namespaceTodoList.Application.TodoLists.Queries.GetSingleTodo;publicclassGetSingleTodoQuery:IRequest<TodoListDto?>{publicGuidListId{get;set;}}publicclassExportTodosQueryHandler:IRequestHandler<GetSingleTodoQuery,TodoListDto?>{privatereadonlyIRepository<Domain.Entities.TodoList>_repository;privatereadonlyIMapper_mapper;publicExportTodosQueryHandler(IRepository<Domain.Entities.TodoList>repository,IMappermapper){_repository=repository;_mapper=mapper;}publicasyncTask<TodoListDto?>Handle(GetSingleTodoQueryrequest,CancellationTokencancellationToken){varspec=newTodoListSpec(request.ListId,true);returnawait_repository.GetAsQueryable(spec).AsNoTracking().ProjectTo<TodoListDto>(_mapper.ConfigurationProvider).FirstOrDefaultAsync(cancellationToken);}}

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

    TodoListController.cs

    //省略其他...[HttpGet("{id:Guid}",Name="TodListById")]publicasyncTask<ActionResult<TodoListDto>>GetSingleTodoList(Guidid){returnawait_mediator.Send(newGetSingleTodoQuery{ListId=id})??thrownewInvalidOperationException();}

    验证

    运行Api项目

    获取所有TodoList列表

    请求

    如何使用AutoMapper实现GET请求

    响应

    如何使用AutoMapper实现GET请求

    获取单个TodoList详情

    请求

    如何使用AutoMapper实现GET请求

    响应

    如何使用AutoMapper实现GET请求

    填一个POST文章里的坑

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

    //省略其他...[HttpPost]publicasyncTask<IActionResult>Create([FromBody]CreateTodoListCommandcommand){varcreatedTodoList=await_mediator.Send(command);//创建成功返回201returnCreatedAtRoute("TodListById",new{id=createdTodoList.Id},createdTodoList);}

    请求

    如何使用AutoMapper实现GET请求

    返回

    Content部分

    如何使用AutoMapper实现GET请求

    以及Header部分

    如何使用AutoMapper实现GET请求

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

     </div> <div class="zixun-tj-product adv-bottom"></div> </div> </div> <div class="prve-next-news">
    本文:如何使用AutoMapper实现GET请求的详细内容,希望对您有所帮助,信息来源于网络。
    上一篇:ThinkPHP中I()和create()方法有哪些区别下一篇:

    6 人围观 / 0 条评论 ↓快速评论↓

    (必须)

    (必须,保密)

    阿狸1 阿狸2 阿狸3 阿狸4 阿狸5 阿狸6 阿狸7 阿狸8 阿狸9 阿狸10 阿狸11 阿狸12 阿狸13 阿狸14 阿狸15 阿狸16 阿狸17 阿狸18