• .net core RESTful Api笔记②


    .net core RESTful Api笔记①中

    写了建立api的工程,和restfulapi介绍和http请求问题,以及内容协商

    Entity Model 和面向外部的Model

     entity model:entity framework core使用entity model是用来表示数据库里面的记录。

    面向外部model:面向外部的model表示传输的东西,这类model优势后叫dto,有时叫viewmodel

    这样就更健壮,可靠,易于进化,同时也是页面最想获得的东西

     修改controller

            public async Task<IActionResult> GetCompanies()
            {
                var companies = await _companyRepository.GetCompaniesAsync();
                var companyDto = new List<CompanyDto>();
                foreach (var company in companies) 
                {
                    companyDto.Add(new CompanyDto
                    {
                        Id = company.Id,
                        Name=company.Name
                    }); 
                }
                return Ok(companyDto);
            }

     IActionResult:也可以写成具体的,可以配合swagger使用

    public async Task<ActionResult<IEnumerable<CompanyDto>>> GetCompanies()
            {
                var companies = await _companyRepository.GetCompaniesAsync();
                var companyDto = new List<CompanyDto>();
                foreach (var company in companies) 
                {
                    companyDto.Add(new CompanyDto
                    {
                        Id = company.Id,
                        Name=company.Name
                    }); 
                }
                return companyDto;
            }

    AutoMapper:对象映射器

    安装:

     注册:

                //获取当前的assembly程序集
                services.AddAutoMapper(AppDomain.CurrentDomain.GetAssemblies());

    创建profile用来映射,修改了之前的dto内容

     

    namespace Rountine.API.Profiles
    {
        public class CompanyProfile:Profile
        {
            public CompanyProfile()
            {
                //这里和注册的方式很像
                //里面的参数是为了在名称映射不相同的情况下手动映射的
                CreateMap<Company, CompanyDto>().ForMember(
                    dest=>dest.CompanyName,
                    opt=>opt.MapFrom(src=>src.Name));
            }
        }
    }

    最后修改controller内容

    using AutoMapper;
    using Microsoft.AspNetCore.Mvc;
    using Rountine.API.Models;
    using Rountine.API.Services;
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Threading.Tasks;
    
    namespace Rountine.API.Controllers
    {
        [ApiController]
        [Route("api/companies")]
        public class CompainesControllercs : ControllerBase
        {
            private readonly ICompanyRepository _companyRepository;
            private readonly IMapper _mapper;
    
            public CompainesControllercs(ICompanyRepository companyRepository, IMapper mapper)
            {
                _companyRepository = companyRepository ?? throw new ArgumentException(nameof(companyRepository));
                _mapper = mapper ?? throw new ArgumentException(nameof(mapper));
            }
            [HttpGet]
            public async Task<ActionResult<IEnumerable<CompanyDto>>> GetCompanies()
            {
                var companies = await _companyRepository.GetCompaniesAsync();
                var companyDto = _mapper.Map<IEnumerable<CompanyDto>>(companies);
                
                return Ok(companyDto);
            }
            [HttpGet("{companyId}")]
            public async Task<ActionResult<CompanyDto>> GetCompanies(Guid companyId)
            {
                var company = await _companyRepository.GetCompanyAsync(companyId);
                if (company == null) {
                    return NotFound();
                }
                var companyDto = _mapper.Map<CompanyDto>(company);
                return Ok(companyDto);
            }
        }
    }

    看下效果:

     父子资源获取方式:

    对于employee的获取不能直接获取它的资源,要体现出公司和员工的关系

    创建employee的model和他的controller

    这是employDto:

     创建EmployeeProfile

    using AutoMapper;
    using Rountine.API.Models;
    using Rountion.API.Eneities;
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Threading.Tasks;
    
    namespace Rountine.API.Profiles
    {
        public class EmployeeProfile:Profile
        {
            public EmployeeProfile()
            {
                CreateMap<Employee, EmployeeDto>()
                    .ForMember(
                        dest=>dest.Name,
                        opt=>opt.MapFrom(src=>$"{src.FirstName}{src.LastName}")
                    )
                    .ForMember(
                        dest=>dest.Gender,
                        opt=>opt.MapFrom(src=>src.Gender.ToString())
                    )
                    .ForMember(
                        dest=>dest.Age,
                        opt=> opt.MapFrom(src=>DateTime.Now.Year-src.DateOfBirth.Year)
                    );
            }
        }
    }

    创建controller

    using AutoMapper;
    using Microsoft.AspNetCore.Mvc;
    using Rountine.API.Models;
    using Rountine.API.Services;
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Threading.Tasks;
    
    namespace Rountine.API.Controllers
    {
        [ApiController]
        [Route("api/companies/{companyId}/employees")]
        public class EmployessController:ControllerBase
        {
            private readonly IMapper mapper;
            private readonly ICompanyRepository companyRepository;
    
            public EmployessController(IMapper mapper,ICompanyRepository companyRepository)
            {
                this.mapper = mapper ?? throw new ArgumentException(nameof(mapper));
                this.companyRepository = companyRepository ??throw new ArgumentNullException(nameof(companyRepository));
            }
            public async Task<ActionResult<IEnumerable<EmployeeDto>>> GetemployessFromCompany(Guid companyId) 
            {
                //判断公司是否存在
                if (!await this.companyRepository.CompanyExistsAsync(companyId)) 
                {
                    return NotFound();
                }
                //这里直接将他们写道一块,本来不应该这样写的
                var employees = await this.companyRepository.GetEmployeesAsynce(companyId);
                //转成dto
                var employessdto = this.mapper.Map<IEnumerable<EmployeeDto>>(employees);
                return Ok(employessdto);
            }
        }
    }

    添加员工种子数据:

                modelBuilder.Entity<Employee>().HasData(
                    new Employee {
                       Id= Guid.Parse("11CCF91A-5E6B-4397-A639-78A18853DDB1"),
                       CompanyId = Guid.Parse("E6573877-FB7D-4BBE-A40A-44D24D8807FA"),
                       EmployeeNo="182844" ,
                       FirstName="li",
                       LastName="ming",
                       Gender=Gender.男,
                DateOfBirth=new DateTime(2000,1,2) },
    new Employee { Id = Guid.Parse("6917B0AA-626D-434A-BDEA-C6E4F9EE35CC"), CompanyId = Guid.Parse("E6573877-FB7D-4BBE-A40A-44D24D8807FA"), EmployeeNo = "182845", FirstName = "liu", LastName = "ming", Gender = Gender.男,
                DateOfBirth = new DateTime(1995, 1, 2) } );

    运行PM>add-migration addEmployeeData

    生成新的语句和快照文件,运行项目,我这里数据一直没生成成功,之后删除了库,重新生成了下数据。

     添加单个查询

            [HttpGet("{employeeId}")]
            public async Task<ActionResult<EmployeeDto>> GetemployesFromCompany(Guid companyId,Guid employeeId)
            {
                //判断公司是否存在
                if (!await this.companyRepository.CompanyExistsAsync(companyId))
                {
                    return NotFound();
                }
                var employee = await this.companyRepository.GetEmployeeAsync(companyId, employeeId);
                if (employee == null) 
                {
                    return NotFound();
                }
                var employeedto= this.mapper.Map<EmployeeDto>(employee);
               
                return Ok(employeedto);
            }

     处理故障

    生产环境可以在管道中配置

                if (env.IsDevelopment())
                {
                    app.UseDeveloperExceptionPage();
                }
                else 
                {
                    app.UseExceptionHandler(appBuilder=> {
                        appBuilder.Run(async context=> {
                            context.Response.StatusCode = 500;
                            await context.Response.WriteAsync("unException error");
                        });
                   

    保证生产环境不暴露api细节。

    Http Head

    head和get几乎一样

    只是有一点不同:head的api不应该返回相应body

    head可以获取资源上获取一些信息

    只用在[httpget]下面加上[httphead]就行了;

    过滤和搜索

    如何绑定api传递数据:

    数据通过多种方式来传递给api。

    binging source attributes 会告诉model绑定引擎从哪绑定的

    [FromBody]:请求的body

    [FromForm]:请求的body中的form

    [FromHeader]:请求的header

    [FromQuery]:querystring中的参数

    [FromRoute]:当前请求路由的数据

    [FromService]:作为action参数注入的服务

    [ApiController]

    默认情况下asp.net core会从complex object model binder,它会把数据从value providers那里提取出来,而value providers的顺序定义好。

    但是我们构建api时会使用[apiController]这个属性,为了是适应api改变的规则。

    [FromBody]:复杂的参数类型

    [FromForm]:推断IFormFile和IFormFileCollextion类型action参数

    [FromRoute]:用来推断Action参数名和路由参数一致情况

    [FromService]:用来推断action参数

    过滤:我们把某个字段名字以及向要让该字段匹配的值一起传递给api,并将这些作为返回集合的一部分。

    例:返回类型是国有企业的的欧洲公司

    get 、api/companies?type=state-owned&region=Europe

    搜索:针对集合进行搜索是指预定义一些规则,把符合条件的数据添加到集合里

    搜索实际超过过滤范围,搜索可能没有

    例:get /api/companies?q=xxx

     这里对员工查询进行修改

     public async Task<IEnumerable<Employee>> GetEmployeesAsynce(Guid companyId,string gender,string q)
            {
                if (companyId == Guid.Empty) {
                    throw new ArgumentNullException(nameof(companyId));
                }
                if (string.IsNullOrEmpty(gender) && string.IsNullOrEmpty(q)) 
                {
                    return await _context.employees.Where(x => x.CompanyId == companyId).OrderBy(x=>x.EmployeeNo).ToListAsync();
                }
                var items = _context.employees.Where(x => x.CompanyId == companyId);
                if (!String.IsNullOrEmpty(gender)) 
                {
                    gender = gender.Trim();
                    items=items.Where(x => x.Gender == Enum.Parse<Gender>(gender));
                }
                if (!string.IsNullOrEmpty(q)) 
                {
                    q = q.Trim();
                    items = items.Where(x => x.EmployeeNo.Contains(q)
                                    ||x.FirstName.Contains(q)
                                    ||x.LastName.Contains(q));
                }
                
                return await items.OrderBy(x => x.EmployeeNo).ToListAsync();
            }

    这里像拼接sql一样按存在拼接到sql上,在return时才去真正的查询。

     上面查询参数都是写在action里,但是会遇到查询条件很多,而且会经常改变需求的查询条件,这样写就很头疼

    所以优化下查询条件

    建立DtoPrameters文件夹下面放上查询类

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Threading.Tasks;
    
    namespace Rountine.API.DtoParameters
    {
        public class CompanyDtoParameters
        {
            public string CompanyName { get; set; }
    
            public string searchTerm { get; set; }
        }
    }

    controller:这里是类传入,要指向querystring才可以,否者默认是body里这样会415错误

            public async Task<ActionResult<IEnumerable<CompanyDto>>> GetCompanies([FromQuery] CompanyDtoParameters parameters)
            {
                var companies = await _companyRepository.GetCompaniesAsync(parameters);
                var companyDto = _mapper.Map<IEnumerable<CompanyDto>>(companies);
                
                return Ok(companyDto);
            }

    sevice:这个思想没变也是先判断都没的情况下,查询,再使用queryable表达式和参数存在情况下一个个判断

            public async Task<IEnumerable<Company>> GetCompaniesAsync(CompanyDtoParameters parameters)
            {
                if (parameters == null) 
                {
                    throw new ArgumentException(nameof(parameters));
                }
                if (string.IsNullOrWhiteSpace(parameters.CompanyName) &&
                    string.IsNullOrWhiteSpace(parameters.searchTerm)) 
                {
                     return await _context.companies.ToListAsync();
                }
                var queryExpression = _context.companies as IQueryable<Company>;
                if (!string.IsNullOrEmpty(parameters.CompanyName)) 
                {
                    parameters.CompanyName = parameters.CompanyName.Trim();
                    queryExpression = queryExpression.Where(x => parameters.CompanyName == x.Name);
                }
                if (!string.IsNullOrEmpty(parameters.searchTerm)) 
                {
                    parameters.searchTerm = parameters.searchTerm.Trim();
                    queryExpression = queryExpression.Where(x => x.introduction.Contains(parameters.searchTerm)
                                                             || x.Name.Contains(parameters.searchTerm));
                }
                return await queryExpression.ToListAsync();
            }

    postman:

  • 相关阅读:
    python 网络爬虫(三)
    python 网络爬虫(二)
    python 网络爬虫(一)
    python 爬虫原理
    (转)栈的生长方向
    CRC校验
    extern关键字
    E
    The Super Powers UVA
    V
  • 原文地址:https://www.cnblogs.com/liuyang95/p/13197443.html
Copyright © 2020-2023  润新知