响应中 location 的设置
示例: 发送POST 请求,进行创建资源的操作。
注意的请求头中content-type 的设置,需要设置成 application/json 类型,并不一定需要json 类型的数据,但默认情况下使用的都是json传输数据,否则asp.net core 会返回 415 状态码。 同时请求体中 也要符合api 接口需要的格式,如果不符合,则会得到 400 的响应码。
在响应头中 包含 location 信息, 标识的新创建的资源的所在。
使用 代码示例:
代码语言:javascript复制 // 这里使用 Name 属性为Action赋值,用于标识,一般跟Action方法名同称
[HttpGet(template:"{CompanyId}", Name = nameof(GetCompany))]
public async Task<IActionResult> GetCompany(Guid companyId)
{
var company = await _companyRepository.GetCompanyAsync(companyId);
if (company == null)
{
return NotFound();
}
return Ok(_mapper.Map<CompanyDTO>(company));
}
// 创建资源的Action
[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);
// CreateRoute 方法 通过传递Action名称,以及一个匿名类 用于拼接完成的url,最后一个响应体的信息
// 该 方法就会在响应头中添加上 location 信息,数值 则是 传递的Action 的访问路径 加上 匿名类设置的属性值,凭借成完整的url返回
return CreatedAtRoute(nameof(GetCompany), new { companyId = returnDto.Id}, returnDto);
}
ASP.NET Core 自定义模型绑定 modelbinder
在复杂的业务逻辑场景下,asp.net core 默认的模型绑定满足不了需要,需要自定义modelbinder
代码语言:javascript复制 // 需要实现 IModelBinder 接口
public class ArrayModelBinder : IModelBinder
{
// 实现 BindModelAsync 方法
public Task BindModelAsync(ModelBindingContext bindingContext)
{
// 验证传递进来的模型元数据是否是 Enumerable 的类型
// 不是则返回失败
if (!bindingContext.ModelMetadata.IsEnumerableType)
{
bindingContext.Result = ModelBindingResult.Failed();
return Task.CompletedTask;
}
// 验证传递进来的模型元数据是否是空数据
// 将模型中的数据转换成 String 类型
var value = bindingContext.ValueProvider.GetValue(bindingContext.ModelName).ToString();
// 验证数据是否是null,或空白字符串
if (String.IsNullOrWhiteSpace(value))
{
bindingContext.Result = ModelBindingResult.Success(null);
return Task.CompletedTask;
}
// 获取到模型的数据的具体类型
var elementType = bindingContext.ModelType.GenericTypeArguments[0];
// 获取一个转换器,将类型转换成指定类型的转换器
var converter = TypeDescriptor.GetConverter(elementType);
// 将模型的数据转换成的String 数据按,分割,通时使用转换器将String数据转换成 转换器指定的类型 的类型数据
var values = value.Split(new[] { "," }, StringSplitOptions.RemoveEmptyEntries).Select(x => converter.ConvertFromString(x.Trim())).ToArray();
// 创建一个指定类型和长度的数组,数组的元素的数值是指定类型的默认值
var typeValues = Array.CreateInstance(elementType, values.Length);
// 将转换后的数据复制给新建的数组
values.CopyTo(typeValues, 0);
// 将放置转换后的数据的数组赋值给model
bindingContext.Model = typeValues;
// 操作成功
bindingContext.Result = ModelBindingResult.Success(typeValues);
return Task.CompletedTask;
}
}
上面的代码是将 用户传递的 类似 1,2,3,4 这样的字符串,通过模型绑定,转换成 IEnumable 类型的数据。
HTTP Options 方法
1、获取服务器支持的HTTP请求方法; 2、用来检查服务器的性能。例如:AJAX进行跨域请求时的预检,需要向另外一个域名的资源发送一个HTTP OPTIONS请求头,用以判断实际发送的请求是否安全。 在 跨域时 CORS 中,使用很多。
Data Annotations 数据验证
asp.net core 内置提供的数据验证方式。 在 System.ComponmentModel.DataAnnotations 命名空间下通过的各种 Attribute,供于使用。
IValidatableObject 接口实现 数据验证
通过实现 IValidatableObject 接口 可以实现更为复杂的数据验证,可以对 数据模型类进行验证,跨属性的验证等。 使用:
代码语言:javascript复制 // 与上面的Data Annotations位于同一命名空间下。
public class EmployeeAdd : IValidatableObject
{
[Display(Name = "员工号"), Required(ErrorMessage = "{0}是必填项"), StringLength(10, MinimumLength = 10, ErrorMessage = "{0}的长度是{1}")]
public String EmployeeNo { get; set; }
[Display(Name = "名"), Required(ErrorMessage = "{0}是必填项"), MaxLength(50, ErrorMessage = "{0}的最大长度不超过{1}")]
public String FirstName { get; set; }
[Display(Name = "姓"), Required(ErrorMessage = "{0}是必填项"), MaxLength(50, ErrorMessage = "{0}的最大长度不超过{1}")]
public String LastName { get; set; }
[Display(Name = "性别")]
public Gender Gender { get; set; }
[Display(Name = "出生日期")]
public DateTime DateOfBirth { get; set; }
// 实现接口,实现方法,在方法中对类进行更复杂的验证
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
if (FirstName == LastName)
{
yield return new ValidationResult(errorMessage: "姓和名不能一致!", memberNames: new[] { nameof(FirstName), nameof(LastName)});
}
}
}
自定义Attribute 数据验证
使用自定义 Attribute 也可以完成复杂的数据验证。 通过继承 ValidationAttribute 类,并重写 IsValid 方法来自定义 Attribute。 使用
代码语言:javascript复制 // 继承 System.ComponmentModel.DataAnnotations 命名空间下的 ValidationAttribute类
public class EmployeeNoMustFromFirstNameAttribute : ValidationAttribute
{
// 重写 IsValid 方法
protected override ValidationResult IsValid(object value, ValidationContext validationContext)
{
// 这里可以完成复杂的验证,
// object value 是 当该attribute 使用在属性上时 可以通过该参数获取到具体的该属性数据
// ValidationContext validationContext 当使用在 类上时,可以通过该参数获取到模型类数据
var addDto = (EmployeeAddDto)validationContext.ObjectInstance;
if (addDto.EmployeeNo == addDto.FirstName)
{
return new ValidationResult(errorMessage: "名称与编号不能一致", memberNames: new[] { nameof(EmployeeAddDto) });
}
return base.IsValid(value, validationContext);
}
}
注意: 一般情况下,asp.net core 内置的data annotations 验证的优先级比较好(可以简单的这样认为),当data annotation 验证报错时则后面的IValidatableObject 接口和自定义 Attribute 则不会在进行验证,这就是一个优先级的问题,而IValidatableObject 接口验证 和 自定义Attribute 的优先级基本一致。