P24 自定义Model绑定器
一组资源,需要一组key
创建新的Action。参数从路由里面获得
.net core允许我们使用自定义的Model绑定。下面就来创建一个自定义的Model绑定器。创建Helpers文件夹。
创建类
它需要实现IModelBinder接口,然后重写方法。ModelBindingContext里面有一些元数据
首先我们的参数是IEnumerable类型的,所以我们要保证ModelBindingContext作用域IEnumerable类型
判断if如果不是作用域Enumerable类型那么就返回失败。
获取的value是个字符串,如果字符串为空的 也表示传递是成功的 返回success
注意最下面的: bindingContext.Model = typedValues;//设置最终的返回结果
最终返回类型
最终再返回Task.CpmpletedTask
value关键字有问题是因为上面有的没有返回值。
把返回值加上就可以了
Controller上使用ModelBinder
处理Post的Action的返回
应该返回的状态是201使用CreateAtRoute
给这个action增加Name值。
运行测试
http://localhost:5000/api/companyCollections
[ { "Name":"Facebook", "Introduction":"A Good Company" }, { "Name":"Twitter", "Introduction":"A Good Company,too" }, { "Name":"SpaceX", "Introduction":"A Good Company,Again" } ]
返回的状态码是201.
在返回的Header里面有个Location的属性。复制这个Location的key
把Location的值复制出来:
http://localhost:5000/api/CompanyCollections/69a5fe4e-e5ca-4256-af58-8b1001c1432b,db773bfc-7d13-45ae-8170-c3dc9427c772,8b263ab0-194c-4778-a072-539e1937ea57
获得了这三个公司信息
在这里加上小括号
这样在请求的时候就可以加上小括号了
这样就很明显的可以看到id的组合用括号括起来
另外这种key value的形式就也可以自定义ModelBinder的形式去写了。
modelBinding 断点跟踪
代码
using System; using System.Collections.Generic; using System.ComponentModel; using System.Linq; using System.Reflection; using System.Threading.Tasks; using Microsoft.AspNetCore.Mvc.ModelBinding; namespace Routine.Api.Helpers { public class ArrayModelBinder : IModelBinder { public Task BindModelAsync(ModelBindingContext bindingContext) { if (!bindingContext.ModelMetadata.IsEnumerableType) { //如果传入的类型不是Enumerable类型的 ,那么就返回失败的消息。 bindingContext.Result = ModelBindingResult.Failed(); return Task.CompletedTask;// } var value = bindingContext.ValueProvider.GetValue(bindingContext.ModelName).ToString();//获取到的就是逗号分隔开的字符串 if (string.IsNullOrWhiteSpace(value)) { bindingContext.Result = ModelBindingResult.Success(null); return Task.CompletedTask;// } var elementType = bindingContext.ModelType.GetTypeInfo().GenericTypeArguments[0]; var converter = TypeDescriptor.GetConverter(elementType);//转换器为了转换字符串为Guid类型 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);//values 复制到TypeValues 从第0个开始拷贝 bindingContext.Model = typedValues;//设置最终的返回结果 bindingContext.Result = ModelBindingResult.Success(bindingContext.Model); return Task.CompletedTask; } } }
using AutoMapper; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using Routine.Api.Entities; using Routine.Api.Helpers; using Routine.Api.Models; using Routine.Api.Servies; using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; namespace Routine.Api.Controllers { [Route("api/[controller]")] [ApiController] public class CompanyCollectionsController : ControllerBase { private readonly ICompanyRepository _companyRespository; private readonly IMapper _mapper; public CompanyCollectionsController(ICompanyRepository companyRepository,IMapper mapper) { _companyRespository = companyRepository ?? throw new ArgumentNullException(nameof(companyRepository)); _mapper = mapper ?? throw new ArgumentNullException(nameof(mapper)); } [HttpPost] public async Task<ActionResult<IEnumerable<CompanyDto>>> CreateCompanyCollection(IEnumerable<CompanyAddDto> companyCollection) { var companyEntities = _mapper.Map<IEnumerable<Company>>(companyCollection); foreach (var company in companyEntities) { _companyRespository.AddCompany(company); } await _companyRespository.SaveAsync(); //return Ok(); var dtosToReturn = _mapper.Map<IEnumerable<CompanyDto>>(companyEntities); var idsString = string.Join(",", dtosToReturn.Select(x => x.Id)); //应该返回的状态是201 所以这里使用CreatedAtRoute return CreatedAtRoute( nameof(GetCompanyCollection), new { ids = idsString }, dtosToReturn); } [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 _companyRespository.GetCompaniesAsync(ids); if (ids.Count() != entities.Count()) { return NotFound(); } //把company的实体转换为dto类 返回前端展示。 var dtosToReturn = _mapper.Map<IEnumerable<CompanyDto>>(entities); return Ok(dtosToReturn); } } }
结束