.net core RESTful Api笔记③

HTTP安全性和幂等性

安全性指的是方法执行后并并不会改变资源的表述

幂等性指的是方法无论执行多少次都会得到同样的结果

 这里创建Company资源:

        [HttpPost]
        public async Task<ActionResult<CompanyDto>> CreateCompany([FromBody]CompanyAddDto company) 
        {
            var entity = _mapper.Map<Company>(company);
            _companyRepository.AddCompany(entity);
            await _companyRepository.SaveAsync();

            var returnDto = _mapper.Map<CompanyDto>(entity);

            return CreatedAtRoute(nameof(GetCompanies),new { companyId= returnDto.Id},returnDto);
        }

里面的CreatedAtRoute返回符合resultful风格,并且需要新的添加dto,映射的addmap也要添加。

为了保证重构方便,而且读取的dto资源不够

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace Rountine.API.Models
{
    public class CompanyAddDto
    {
        public string Name { get; set; }
        public string introduction { get; set; }
    }
}

添加employee资源:

也是和上面比较类似

 [HttpPost]
        public async Task<ActionResult<EmployeeDto>> CreaterEmployeeForCompany(Guid companyId,EmployeeAddDto employee) 
        {
            if (!await this.companyRepository.CompanyExistsAsync(companyId)) 
            {
                return NotFound();

            }
            var entity = mapper.Map<Employee>(employee);

            companyRepository.AddEmployee(companyId,entity);
            await companyRepository.SaveAsync();

            var dtoToReturn = mapper.Map<EmployeeDto>(entity);
            return CreatedAtRoute(nameof(GetemployesFromCompany),new {CompanyId= companyId, employeeId= dtoToReturn.Id }, dtoToReturn);
        }

AddDto:

using Rountion.API.Eneities;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace Rountine.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; }
    }
}

同时创建父子资源:

修改CompanyAddDto:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace Rountine.API.Models
{
    public class CompanyAddDto
    {
        public string Name { get; set; }
        public string introduction { get; set; }
        public ICollection<EmployeeAddDto> Employee { get; set; } = new List<EmployeeAddDto>();
    }
}

结果:

 创建多个资源:

controller:

using AutoMapper;
using Microsoft.AspNetCore.Mvc;
using Rountine.API.Models;
using Rountine.API.Services;
using Rountion.API.Eneities;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace Rountine.API.Controllers
{
    [ApiController]
    [Route("api/companycollections")]
    public class CompanyCollectionsController:ControllerBase
    {
        private readonly IMapper _mapper;
        private readonly ICompanyRepository _companyRepository;
        public CompanyCollectionsController(ICompanyRepository companyRepository, IMapper mapper) 
        {
            _mapper = mapper??throw new ArgumentException(nameof(mapper));
            _companyRepository = companyRepository?? throw new ArgumentException(nameof(companyRepository));
        }
        [HttpPost]
        public async Task<ActionResult<IEnumerable<CompanyDto>>> CreateCompanyCollections(IEnumerable<CompanyAddDto> companies) 
        {
            var companyEntities = _mapper.Map<IEnumerable<Company>>(companies);
            foreach (var company in companyEntities) 
            {
                _companyRepository.AddCompany(company);
            }
            await _companyRepository.SaveAsync();
            return Ok();
        }
    }
}

 这里返回时200,正常的应该返回201,所以这里还需要修改下

修改方式也比较麻烦:

controller:里面修改创建并添加了查询保证201状态码和返回添加的内容

using AutoMapper;
using Microsoft.AspNetCore.Mvc;
using Rountine.API.Helpers;
using Rountine.API.Models;
using Rountine.API.Services;
using Rountion.API.Eneities;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace Rountine.API.Controllers
{
    [ApiController]
    [Route("api/companycollections")]
    public class CompanyCollectionsController : ControllerBase
    {
        private readonly IMapper _mapper;
        private readonly ICompanyRepository _companyRepository;
        public CompanyCollectionsController(ICompanyRepository companyRepository, IMapper mapper)
        {
            _mapper = mapper ?? throw new ArgumentException(nameof(mapper));
            _companyRepository = companyRepository ?? throw new ArgumentException(nameof(companyRepository));
        }

        [HttpGet("{ids}",Name=nameof(GetCompanyCollection))]
        public async Task<IActionResult> GetCompanyCollection(
            [FromRoute]
            [ModelBinder(BinderType=typeof(ArrayModelBinder))]IEnumerable<Guid> ids) 
        {
            if (ids == null) 
            {
                return BadRequest();
            }
            var entities = await _companyRepository.GetCompaniesAsync(ids);

            if (ids.Count() != entities.Count()) 
            {
                return NotFound();
            }
            var dtotoreturn = _mapper.Map<IEnumerable<CompanyDto>>(entities);
            return Ok(dtotoreturn);
        }

        [HttpPost]
        public async Task<ActionResult<IEnumerable<CompanyDto>>> CreateCompanyCollections(IEnumerable<CompanyAddDto> companies) 
        {
            var companyEntities = _mapper.Map<IEnumerable<Company>>(companies);
            foreach (var company in companyEntities) 
            {
                _companyRepository.AddCompany(company);
            }
            await _companyRepository.SaveAsync();
            var dtosToReturn = _mapper.Map<IEnumerable<CompanyDto>>(companyEntities);

            var idsString = string.Join(",",dtosToReturn.Select(x=>x.Id));

            return CreatedAtRoute(nameof(GetCompanyCollection),new { ids = idsString }, dtosToReturn);
        }
    }
}

这里需要将传入的ids转化成IEnumerable<Guid>所以需要自定义一个model类型将传入的转化成guid

ArrayModelBinder:

using Microsoft.AspNetCore.Mvc.ModelBinding;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Reflection;
using System.Threading.Tasks;

namespace Rountine.API.Helpers
{

    public class ArrayModelBinder : IModelBinder
    {
        public Task BindModelAsync(ModelBindingContext bindingContext)
        {
            if (!bindingContext.ModelMetadata.IsEnumerableType) 
            {
                bindingContext.Result = ModelBindingResult.Failed();
                return Task.CompletedTask;
            }
            var value = bindingContext.ValueProvider.GetValue(bindingContext.ModelName).ToString();
            if (string.IsNullOrEmpty(value)) 
            {
                bindingContext.Result = ModelBindingResult.Success(null);
                return Task.CompletedTask;
            }
            var elementType = bindingContext.ModelType.GetTypeInfo().GenericTypeArguments[0];
            var converter = TypeDescriptor.GetConverter(elementType);
            var values = value.Split(new[] { "," }, StringSplitOptions.RemoveEmptyEntries).Select(x=>converter.ConvertFromString(x.Trim())).ToArray() ;

            var typedValues = Array.CreateInstance(elementType,values.Length);
            values.CopyTo(typedValues,0);
            bindingContext.Model = typedValues;

            bindingContext.Result = ModelBindingResult.Success(bindingContext.Model);
            return Task.CompletedTask;
        }
    }
}

请求:

原文地址:https://www.cnblogs.com/liuyang95/p/13206054.html