• 使用ASP.NET Core 3.x 构建 RESTful API P21 P22 创建资源 创建子资源


    使用ASP.NET Core 3.x 构建 RESTful API P21 P22 创建资源 创建子资源


    博客园文章Id:12678771


    创建父资源

    根据经验,我们在做查询,创建,更新时,我们应该使用不同的Dto类,虽然绝大多数时候,可能他们的成员是一样的,但是业务是变化的,创建不同的Dto类的好处,在于可以快速的方便我们对于某一块业务进行重构.

    下面我们开始编写用于创建公司资源的API

    [HttpPost]
    public async Task<ActionResult<CompanyDto>> CreateCompany([FromBody]CompanyAddDto company)
    {
                //当请求的Body转换成CompanyAddDto失败时,company就会为null,(在.Net Core 3.x之前,
                //因为早期版本是没有ApiController这个特性的)所以我们在此处应该判断一下,
                //但是在.Net Core 3.x (添加[ApiController特性])之后,当请求的Body转换失败之后,.Net Core 3.x 会自动返回 400 状态码,所以下面的if判断可以不写.
                if (company == null)
                {
                    return BadRequest();
                }
    
                var entity = this._mapper.Map<Company>(company);
    
                this._companyRepository.AddCompany(entity);
    
                await this._companyRepository.SaveAsync();
    
                //POST请求成功之后之后,我们应该返回201状态码
    
                var returnDto = this._mapper.Map<CompanyDto>(entity);
    
                //返回插入的资源
                //第一个参数:返回可找到当前资源的URI
                //第二个参数:路由的值
                //第三个参数:返回的是响应的Body
                return CreatedAtRoute(
                    nameof(GetCompany),
                    new{companyId = returnDto.Id},
                    returnDto);
    }

    在上述代码中,CreatedAtRoute方法的第一个参数,是返回可以查询到当前创建的资源的URI指向的Action方法,所以我们需要给该方法起一个名称代码如下:

     /// <summary>
     /// 获取指定公司
     /// </summary>
     /// <param name="companyId">公司id</param>
     /// <returns></returns>
     [HttpGet("{companyId}",Name =nameof(GetCompany) )]  //注意此处的Name属性
     //[Route("{companyId}")]   //使用这种方式也能表示路由,但是不常用
     public async Task<ActionResult<Company>> GetCompany(Guid companyId)

    创建用于添加公司资源的Dto对象的代码如下:

     /// <summary>
     /// 创建公司的Dto对象
     /// </summary>
     public class CompanyAddDto
     {
         
         public string Name { get; set; }
         public string Introduction { get; set; }
    
     }

    CompanyProfile.cs类中,映射 CompanyAddDto 与 表示实体 Comapny 的映射关系,代码如下:

    /*
     * CompanyAddDto(原对象),Company(目标对象)的映射
     */
    CreateMap<CompanyAddDto,Company>();

    优化实现类添加公司部分的代码:

    public void AddCompany(Company company)
    {
        if (company == null)
        {
            throw new ArgumentException(nameof(company));
        }
    
        company.Id = Guid.NewGuid();
    
        if (company.Employees !=null)
        {
            foreach (var employee in company.Employees)
            {
                employee.Id = Guid.NewGuid();
            }
    
        }
    
        this._content.Add(company);
        //this._content.Companies.AddAsync(company);
    }
    

    调用创建公司资源接口:

    调用
    调用

    调用结果:

    调用结果
    调用结果

    返回的Handers:

    返回的Handers
    返回的Handers

    我们可以看到在返回的Headers中已经包含了,可以再一次请求到当前插入的资源URI
    Location Header :http://localhost:5000/api/Companies/663b20a2-dadc-4502-a99d-57a26810530b

    请求当前资源
    请求当前资源

    故意不传参数查看插入结果,通过返回结果可知返回了400状态码,而这个自动化的过程,由[ApiController]特性实现.

    调用结果
    调用结果

    创建子资源

    一个公司一般认为有多个员工,那么公司在这个关系中,就相当于父资源,员工就相当于子资源.

    编写接收传入参数的Dto,代码如下:

    
    using System;
    using Routine.Api.Entitle;
    
    namespace Routine.Api.Models
    {
        public class EmployeeAddDto
        {
            public string EmployeeNo { get; set; }
            public string FirstName { get; set; }
            public string LastName { get; set; }
            public Gender Gender { get; set; }
            public DateTime DateOfBirth { get; set; }
        }
    }
    

    EmployeeProfile.cs类中配置 Employee 与 EmployeeAddDto的映射关系:

    //配置映射
    //第一个参数: 源对象
    //第二个参数: 目标对象
    CreateMap<EmployeeAddDto, Employee>();

    编写创建子资源的API,代码如下:

    [HttpPost]
    public async Task<ActionResult<EmployeeDto>> CreateEmployeeForCompany(Guid companyId,[FromBody] EmployeeAddDto employee)
    {
        if (!await this._companyRepository.CompanyExistsAsync(companyId))
        {
            return NotFound();
        }
    
        //此处的if可以不写因为框架已经保证了,当闯入的创建资源的参数无法被解析会自动返回415的Http状态码
        if (employee == null)
        {
            return BadRequest();
        }
    
        //使用AutoMapper将请求的Dto转换成Entity
        var entity = this._mapper.Map<Employee>(employee);
    
        this._companyRepository.AddEmployee(companyId,entity);
    
        await this._companyRepository.SaveAsync();
    
        var dtoToReturn = this._mapper.Map<EmployeeDto>(entity);
    
        //返回插入的资源
        //第一个参数:返回可找到当前资源的URI
        //第二个参数:路由的值
        //第三个参数:返回的是响应的Body
        return CreatedAtRoute(
            nameof(GetEmployeeForCompany),
            new { companyId = companyId, employeeId = dtoToReturn.Id },
            dtoToReturn);
    }

    根据返回的Headers我们需要给找到当前创建的资源的API起一个路由别名,所以我们需要修改GetEmployeeForCompany的路由规则特性,代码如下:

    [HttpGet("{employeeId}", Name = nameof(GetEmployeeForCompany))]
    public async Task<ActionResult<EmployeeDto>> GetEmployeeForCompany(Guid companyId, Guid employeeId)

    调用及返回调用结果:

    配置请求的Headers:

    配置请求Headers
    配置请求Headers

    调用:

    调用
    调用

    返回的结果:

    返回的结果
    返回的结果

    返回的Headers:

    返回的Headers
    返回的Headers

    我们注意到返回的Headers中包含了,Location信息. Location信息的值,就是可以再一次请求到创建的资源的URI.

  • 相关阅读:
    测试用例的设计
    测试经理的职责
    如果开发认为这不是bug,对QA来说应该怎么处理?
    我选择测试的过程
    API的知识点
    测试人员需要的技能
    时区转换的计算方式
    学习能力的必需
    制图工具
    JSON序列和反序列1
  • 原文地址:https://www.cnblogs.com/HelloZyjS/p/12678771.html
Copyright © 2020-2023  润新知