PUT:整体更新/替换
资源所有的字段都被重写了,或者是设置为该字段的默认值
PATCH: 局部更新
使用JsonPatchDocument发送变更的数据,对资源指定的字段进行更新
[HttpPut("{employeeId}")]
public async Task UpdateEmployeeForCompany(
Guid companyId,
Guid employeeId,
EmployeeUpdateDto employee)
{
if (!await companyRepository.CompanyExistsAsync(companyId))
{
return NotFound();
}
var employeeEntity = await companyRepository.GetEmployeeAsync(companyId, employeeId);
if (employeeEntity == null)
{
var employeeToAddEntity = mapper.Map(employee);
employeeToAddEntity.Id = employeeId;
companyRepository.AddEmployee(companyId, employeeToAddEntity);
await companyRepository.SaveAsync();
var dtoToReturn = mapper.Map(employeeToAddEntity);
return CreatedAtRoute(nameof(GetEmployeeForCompany), new
{
companyId,
employeeId = dtoToReturn.Id
}, dtoToReturn);
}
//entity 转化为updateDto
//把传进来的employee的值更新到updateDto
//把updateDto映射回entity
mapper.Map(employee, employeeEntity);
companyRepository.UpdateEmployee(employeeEntity);
await companyRepository.SaveAsync();
return NoContent(); //204
}
Patch使用方法:
///
/// 局部更新Employee
///
///
///
///
///
[HttpPatch("{employeeId}")]
public async Task PartiallyUpdateEmployeeForCompany(
Guid companyId,
Guid employeeId,
JsonPatchDocument patchDocument)
{
if (!await companyRepository.CompanyExistsAsync(companyId))
{
return NotFound();
}
var employeeEntity = await companyRepository.GetEmployeeAsync(companyId, employeeId);
//如果不存在则创建
if (employeeEntity == null)
{
var employeeDto = new EmployeeUpdateDto();
patchDocument.ApplyTo(employeeDto, ModelState);
if (!TryValidateModel(employeeDto))
{
return ValidationProblem(ModelState);
}
var employeeToAdd = mapper.Map(employeeDto);
employeeToAdd.Id = employeeId;
companyRepository.AddEmployee(companyId, employeeToAdd);
await companyRepository.SaveAsync();
var dtoToReturn = mapper.Map(employeeToAdd);
return CreatedAtRoute(nameof(GetEmployeeForCompany), new
{
companyId,
employeeId = dtoToReturn.Id
}, dtoToReturn);
}
var dtoToPatch = mapper.Map(employeeEntity);
//需要处理验证错误
patchDocument.ApplyTo(dtoToPatch, ModelState);
if (!TryValidateModel(dtoToPatch))
{
return ValidationProblem(ModelState);//400 BadRequest
}
mapper.Map(dtoToPatch, employeeEntity);
companyRepository.UpdateEmployee(employeeEntity);
await companyRepository.SaveAsync();
return NoContent();
}
POST:
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers(configure: setup =>
{
setup.ReturnHttpNotAcceptable = true;
})
.AddNewtonsoftJson(setup =>
{
setup.SerializerSettings.ContractResolver =
new CamelCasePropertyNamesContractResolver();
})
}
///
/// 使用自定义的错误验证报告信息
///
///
///
public override ActionResult ValidationProblem([ActionResultObjectValue] ModelStateDictionary modelStateDictionary)
{
var options = HttpContext.RequestServices
.GetRequiredService>();
return (ActionResult)options.Value.InvalidModelStateResponseFactory(ControllerContext);
}
[HttpDelete]
public async Task DeleteEmployeeForCompany(Guid companyId, Guid employeeId)
{
if (!await companyRepository.CompanyExistsAsync(companyId))
{
return NotFound();
}
var employeeEnttiy = await companyRepository.GetEmployeeAsync(companyId, employeeId);
if (employeeEnttiy == null)
{
return NotFound();
}
companyRepository.DeleteEmployee(employeeEnttiy);
await companyRepository.SaveAsync();
return NoContent();
}
集合资源的数量通常比较大,需要对它们进行分页查询
避免性能问题
参数通过Query String进行传递
api/companies?pageNumber=1&pageSize=5
每页的笔数需要进行控制
默认就应该分页
应该对底层的数据存储进行分页
namespace Routine.Api.ResourceParameters
{
public class CompanyDtoParameter
{
private const int MaxPageSize = 20;
public string CompanyName { get; set; }
public string SearchTerm { get; set; }
public int PageNumber { get; set; } = 1;
private int pageSize = 5;
public int PageSize
{
get => pageSize;
set => pageSize = (value > MaxPageSize) ? MaxPageSize : value;
}
}
}
PagedList类定义
ResourceUriType:
namespace Routine.Api.Helpers
{
public enum ResourceUriType
{
PreviousePage,
NextPage
}
}
using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace Routine.Api.Helpers
{
public class PagedList : List
{
public int CurrentPage { get; set; }
public int TotalPages { get; set; }
public int PageSize { get; set; }
public int TotalCount { get; set; }
public bool HasPrevious => CurrentPage > 1;
public bool HasNext => CurrentPage < TotalPages;
public PagedList(List items, int count, int pageNumber, int pageSize)
{
TotalCount = count;
PageSize = pageSize;
CurrentPage = pageNumber;
TotalPages = (int)Math.Ceiling(count / (double)PageSize);
AddRange(items);
}
public static async Task> CreateAsync(IQueryable source, int pageNumber, int pageSize)
{
var count = await source.CountAsync();
var items = await source.Skip((pageNumber - 1) * pageSize).Take(pageSize).ToListAsync();
return new PagedList(items, count, pageNumber, pageSize);
}
}
}
查询定义:
public async Task> GetCompaniesAsync(CompanyDtoParameter parameter)
{
if (parameter == null)
{
throw new ArgumentNullException(nameof(parameter));
}
var queryExpression = context.Companies as IQueryable;
if (!string.IsNullOrWhiteSpace(parameter.CompanyName))
{
queryExpression = queryExpression.Where(x => x.Name == parameter.CompanyName.Trim());
}
if (!string.IsNullOrWhiteSpace(parameter.SearchTerm))
{
queryExpression = queryExpression.Where(x => x.Name == parameter.SearchTerm.Trim() ||
x.Introduction.Contains(parameter.SearchTerm.Trim()));
}
//分页
//queryExpression = queryExpression
// .Skip(parameter.PageSize * (parameter.PageNumber - 1))
// .Take(parameter.PageSize);
//return await queryExpression.ToListAsync();
return await PagedList.CreateAsync(queryExpression, parameter.PageNumber, parameter.PageSize);
}
Controller中使用分页:
[HttpGet(Name = nameof(GetCompanies))]
[HttpHead]
public async Task>> GetCompanies([FromQuery]CompanyDtoParameter parameter = null)
{
//var companies = await companyRepository.GetCompaniesAsync();
//return Ok(companies);
//CompanyDtoParameter parameter = null;
var companies = await companyRepository.GetCompaniesAsync(parameter);
//var companyDtos = new List();
//foreach (var item in companies)
//{
// companyDtos.Add(new CompanyDto()
// {
// Id = item.Id,
// CompanyName = item.Name
// });
//}
var previousPageLink = companies.HasPrevious
? CreateCompaniesResourceUri(parameter, ResourceUriType.PreviousePage)
: null;
var nextPageLink = companies.HasNext
? CreateCompaniesResourceUri(parameter, ResourceUriType.NextPage)
: null;
var paginationMetadata = new
{
totalCount = companies.TotalCount,
pageSize = companies.PageSize,
currentPage = companies.CurrentPage,
totalPages = companies.TotalPages,
previousPageLink,
nextPageLink
};
//在Response头部,添加分页信息
Response.Headers.Add("X-Pagination", JsonSerializer.Serialize(paginationMetadata, new JsonSerializerOptions()
{
Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping
}));
var companyDtos = mapper.Map>(companies);
return Ok(companyDtos);
}
///
/// 创建分页url
///
///
///
///
private string CreateCompaniesResourceUri(CompanyDtoParameter parameter, ResourceUriType type)
{
switch (type)
{
case ResourceUriType.PreviousePage:
return Url.Link(nameof(GetCompanies), new
{
pageNumber = parameter.PageNumber - 1,
pageSize = parameter.PageSize,
companyName = parameter.CompanyName,
searchTerm = parameter.SearchTerm
});
case ResourceUriType.NextPage:
return Url.Link(nameof(GetCompanies), new
{
pageNumber = parameter.PageNumber + 1,
pageSize = parameter.PageSize,
companyName = parameter.CompanyName,
searchTerm = parameter.SearchTerm
});
default:
return Url.Link(nameof(GetCompanies), new
{
pageNumber = parameter.PageNumber,
pageSize = parameter.PageSize,
companyName = parameter.CompanyName,
searchTerm = parameter.SearchTerm
});
}
}