溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

如何使用AutoMapper實(shí)現(xiàn)GET請(qǐng)求

發(fā)布時(shí)間:2021-12-27 16:54:52 來(lái)源:億速云 閱讀:164 作者:iii 欄目:開(kāi)發(fā)技術(shù)

這篇文章主要講解了“如何使用AutoMapper實(shí)現(xiàn)GET請(qǐng)求”,文中的講解內(nèi)容簡(jiǎn)單清晰,易于學(xué)習(xí)與理解,下面請(qǐng)大家跟著小編的思路慢慢深入,一起來(lái)研究和學(xué)習(xí)“如何使用AutoMapper實(shí)現(xiàn)GET請(qǐng)求”吧!

    需求

    需求很簡(jiǎn)單:實(shí)現(xiàn)GET請(qǐng)求獲取業(yè)務(wù)數(shù)據(jù)。在這個(gè)階段我們經(jīng)常使用的類庫(kù)是AutoMapper。

    目標(biāo)

    合理組織并使用AutoMapper,完成GET請(qǐng)求。

    原理與思路

    首先來(lái)簡(jiǎn)單地介紹一下這這個(gè)類庫(kù)。

    關(guān)于AutoMapper

    在業(yè)務(wù)側(cè)代碼和數(shù)據(jù)庫(kù)實(shí)體打交道的過(guò)程中,一個(gè)必不可少的部分就是返回的數(shù)據(jù)類型轉(zhuǎn)換。對(duì)于不同的請(qǐng)求來(lái)說(shuō),希望得到的返回值是數(shù)據(jù)庫(kù)實(shí)體的一部分/組合/計(jì)算等情形。我們就經(jīng)常需要手寫(xiě)用于數(shù)據(jù)對(duì)象轉(zhuǎn)換的代碼,但是轉(zhuǎn)換前后可能大部分情況下有著相同名稱的字段或?qū)傩?。這部分工作能避免手寫(xiě)冗長(zhǎng)的代碼嗎?可以。

    我們希望接受的請(qǐng)求和返回的值(統(tǒng)一稱為model)具有以下兩點(diǎn)需要遵循的原則:

    1.每個(gè)model被且只被一個(gè)API消費(fèi);

    2.每個(gè)model里僅僅包含API發(fā)起方希望包含的必要字段或?qū)傩浴?/p>

    AutoMapper庫(kù)就是為了實(shí)現(xiàn)這個(gè)需求而存在的,它的具體用法請(qǐng)參考官方文檔,尤其是關(guān)于Convention的部分,避免重復(fù)勞動(dòng)。

    實(shí)現(xiàn)

    所有需要使用AutoMapper的地方都集中在Application項(xiàng)目中。

    引入AutoMapper

    $ dotnet add src/TodoList.Application/TodoList.Application.csproj package AutoMapper.Extensions.Microsoft.DependencyInjection

    然后在Application/Common/Mappings下添加配置,提供接口的原因是我們后面就可以在DTO里實(shí)現(xiàn)各自對(duì)應(yīng)的Mapping規(guī)則,方便查找。

    IMapFrom.cs

    using AutoMapper;
    
    namespace TodoList.Application.Common.Mappings;
    
    public interface IMapFrom<T>
    {
        void Mapping(Profile profile) => profile.CreateMap(typeof(T), GetType());
    }

    MappingProfile.cs

    using System.Reflection;
    using AutoMapper;
    
    namespace TodoList.Application.Common.Mappings;
    
    public class MappingProfile : Profile
    {
        public MappingProfile() => ApplyMappingsFromAssembly(Assembly.GetExecutingAssembly());
    
        private void ApplyMappingsFromAssembly(Assembly assembly)
        {
            var types = assembly.GetExportedTypes()
                .Where(t => t.GetInterfaces().Any(i =>
                    i.IsGenericType && i.GetGenericTypeDefinition() == typeof(IMapFrom<>)))
                .ToList();
    
            foreach (var type in types)
            {
                var instance = Activator.CreateInstance(type);
    
                var methodInfo = type.GetMethod("Mapping")
                                 ?? type.GetInterface("IMapFrom`1")!.GetMethod("Mapping");
    
                methodInfo?.Invoke(instance, new object[] { this });
            }
        }
    }

    DependencyInjection.cs進(jìn)行依賴注入:

    DependencyInjection.cs

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

    實(shí)現(xiàn)GET請(qǐng)求

    在本章中我們只實(shí)現(xiàn)TodoListQuery接口(GET),并且在結(jié)果中包含TodoItem集合,剩下的接口后面的文章中逐步涉及。

    GET All TodoLists

    Application/TodoLists/Queries/下新建一個(gè)目錄GetTodos用于存放創(chuàng)建一個(gè)TodoList相關(guān)的所有邏輯:

    定義TodoListBriefDto對(duì)象:

    TodoListBriefDto.cs

    using TodoList.Application.Common.Mappings;
    
    namespace TodoList.Application.TodoLists.Queries.GetTodos;
    
    // 實(shí)現(xiàn)IMapFrom<T>接口,因?yàn)榇薉to不涉及特殊字段的Mapping規(guī)則
    // 并且屬性名稱與領(lǐng)域?qū)嶓w保持一致,根據(jù)Convention規(guī)則默認(rèn)可以完成Mapping,不需要額外實(shí)現(xiàn)
    public class TodoListBriefDto : IMapFrom<Domain.Entities.TodoList>
    {
        public Guid Id { get; set; }
        public string? Title { get; set; }
        public string? Colour { get; set; }
    }

    GetTodosQuery.cs

    using AutoMapper;
    using AutoMapper.QueryableExtensions;
    using MediatR;
    using Microsoft.EntityFrameworkCore;
    using TodoList.Application.Common.Interfaces;
    
    namespace TodoList.Application.TodoLists.Queries.GetTodos;
    
    public class GetTodosQuery : IRequest<List<TodoListBriefDto>>
    {
    }
    
    public class GetTodosQueryHandler : IRequestHandler<GetTodosQuery, List<TodoListBriefDto>>
    {
        private readonly IRepository<Domain.Entities.TodoList> _repository;
        private readonly IMapper _mapper;
    
        public GetTodosQueryHandler(IRepository<Domain.Entities.TodoList> repository, IMapper mapper)
        {
            _repository = repository;
            _mapper = mapper;
        }
    
        public async Task<List<TodoListBriefDto>> Handle(GetTodosQuery request, CancellationToken cancellationToken)
        {
            return await _repository
                .GetAsQueryable()
                .AsNoTracking()
                .ProjectTo<TodoListBriefDto>(_mapper.ConfigurationProvider)
                .OrderBy(t => t.Title)
                .ToListAsync(cancellationToken);
        }
    }

    最后實(shí)現(xiàn)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相關(guān)的所有邏輯:

    定義TodoItemDtoTodoListDto對(duì)象:

    TodoItemDto.cs

    using AutoMapper;
    using TodoList.Application.Common.Mappings;
    using TodoList.Domain.Entities;
    
    namespace TodoList.Application.TodoItems.Queries.GetTodoItems;
    
    // 實(shí)現(xiàn)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; }
    
        // 實(shí)現(xiàn)接口定義的Mapping方法,并提供除了Convention之外的特殊字段的轉(zhuǎn)換規(guī)則
        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;
    
    // 實(shí)現(xiàn)IMapFrom<T>接口,因?yàn)榇薉to不涉及特殊字段的Mapping規(guī)則
    // 并且屬性名稱與領(lǐng)域?qū)嶓w保持一致,根據(jù)Convention規(guī)則默認(rèn)可以完成Mapping,不需要額外實(shí)現(xiàn)
    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>();
    }

    創(chuàng)建一個(gè)根據(jù)ListId來(lái)獲取包含TodoItems子項(xiàng)的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));
            }
        }
    }

    我們?nèi)匀粸檫@個(gè)查詢新建一個(gè)GetSingleTodo目錄,并實(shí)現(xiàn)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 class 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返回的問(wèn)題,后文會(huì)有使用。

    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();
    }

    驗(yàn)證

    運(yùn)行Api項(xiàng)目

    獲取所有TodoList列表

    請(qǐng)求

    如何使用AutoMapper實(shí)現(xiàn)GET請(qǐng)求

    響應(yīng)

    如何使用AutoMapper實(shí)現(xiàn)GET請(qǐng)求

    獲取單個(gè)TodoList詳情

    請(qǐng)求

    如何使用AutoMapper實(shí)現(xiàn)GET請(qǐng)求

    響應(yīng)

    如何使用AutoMapper實(shí)現(xiàn)GET請(qǐng)求

    填一個(gè)POST文章里的坑

    在使用.NET 6開(kāi)發(fā)TodoList應(yīng)用(6)——使用MediatR實(shí)現(xiàn)POST請(qǐng)求中我們留了一個(gè)問(wèn)題,即創(chuàng)建TodoList后的返回值當(dāng)時(shí)我們是臨時(shí)使用Id返回的,推薦的做法是下面這樣:

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

    請(qǐng)求

    如何使用AutoMapper實(shí)現(xiàn)GET請(qǐng)求

    返回

    Content部分

    如何使用AutoMapper實(shí)現(xiàn)GET請(qǐng)求

    以及Header部分

    如何使用AutoMapper實(shí)現(xiàn)GET請(qǐng)求

    我們主要觀察返回的HTTPStatusCode是201,并且在Header中l(wèi)ocation字段表明了創(chuàng)建資源的位置。

    感謝各位的閱讀,以上就是“如何使用AutoMapper實(shí)現(xiàn)GET請(qǐng)求”的內(nèi)容了,經(jīng)過(guò)本文的學(xué)習(xí)后,相信大家對(duì)如何使用AutoMapper實(shí)現(xiàn)GET請(qǐng)求這一問(wèn)題有了更深刻的體會(huì),具體使用情況還需要大家實(shí)踐驗(yàn)證。這里是億速云,小編將為大家推送更多相關(guān)知識(shí)點(diǎn)的文章,歡迎關(guān)注!

    向AI問(wèn)一下細(xì)節(jié)

    免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

    AI