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;
        }
    }
}
ArrayModelBinder

 

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);
        }
    }
}
CompanyCollectionsController

 

 

结束

 

posted @ 2020-03-22 19:07  高山-景行  阅读(253)  评论(0编辑  收藏  举报