参照 草根专栏- ASP.NET Core + Ng6 实战:https://v.qq.com/x/page/u0765jbwc6f.html

一、POST

安全性和幂等性

  1. 安全性是指方法执行后并不会改变资源的表述
  2. 幂等性是指方法无论执行多少次都会得到同样的结果

POST添加资源:

  • 不安全, 不幂等
  • 参数 [FromBody]
  • 返回 201 Create :    CreatedAtRoute(): 它允许响应里带着Location Header,在这个Location Header里包含着一个uri,通过这个uri就可以GET到我们刚刚创建好的资源
  • HATEOAS

(1)添加 PostAddResource.cs 类

  1. namespace BlogDemo.Infrastructure.Resources
  2. {
  3. public class PostAddResource
  4. {
  5. public string Title { get; set; }
  6. public string Body { get; set; }
  7.  
  8. public string Remark { get; set; }
  9. }
  10. }

(2)添加映射

  1. namespace BlogDemo.Api.Extensions
  2. {
  3. public class MappingProfile:Profile
  4. {
  5. public MappingProfile()
  6. {
  7. CreateMap<Post, PostDTO>().ForMember(dest=>dest.Updatetime,opt=>opt.MapFrom(src=>src.LastModified));
  8. CreateMap<PostDTO, Post>();
  9. CreateMap<PostAddResource, Post>();
  10. }
  11. }
  12. }

(3)添加post方法:

  1. [HttpPost(Name = "CreatePost")]
  2. public async Task<IActionResult> Post([FromBody] PostAddResource postAddResource)
  3. {
  4. if (postAddResource == null)
  5. {
  6. return BadRequest();
  7. }
  8.  
  9. var newPost = _mapper.Map<PostAddResource, Post>(postAddResource);
  10.  
  11. newPost.Author = "admin";
  12. newPost.LastModified = DateTime.Now;
  13.  
  14. _postRepository.AddPost(newPost);
  15.  
  16. if (!await _unitOfWork.SaveAsync())
  17. {
  18. throw new Exception("Save Failed!");
  19. }
  20.  
  21. var resultResource = _mapper.Map<Post, PostDTO>(newPost);
  22.  
  23. var links = CreateLinksForPost(newPost.Id);
  24. var linkedPostResource = resultResource.ToDynamic() as IDictionary<string, object>;
  25. linkedPostResource.Add("links", links);
  26.  
  27. return CreatedAtRoute("GetPost", new { id = linkedPostResource["Id"] }, linkedPostResource);
  28. }

(4) 测试:

二、Model验证:

          定义验证规则
          检查验证规则
          把验证错误信息发送给API的消费者

1、验证方式:

          内置验证:
               DataAnnotation
               ValidationAttribute
              IValidatebleObject
          第三方: FluentValidation

2、使用FluentValidation组件(关注点分离)

(1) 安装: 

FluentValidation.AspNetCore
                  FluentValidation

(2) 为每一个Resource建立验证器:

继承AbstractValidator<T>

  1. namespace BlogDemo.Infrastructure.Resources
  2. {
  3. public class PostAddResourceValidator:AbstractValidator<PostAddResource>
  4. {
  5. public PostAddResourceValidator()
  6. {
  7. RuleFor(x => x.Title).NotEmpty()
  8. .WithName("标题").WithMessage("{PropertyName}是必须填写的")
  9. .MaximumLength().WithMessage("{PropertyName}的最大长度是{MaxLength}");
  10.  
  11. RuleFor(x => x.Body).NotEmpty()
  12. .WithName("正文").WithMessage("{PropertyName}是必须填写的")
  13. .MinimumLength().WithMessage("{PropertyName}的最大长度是{MinLength}");
  14. }
  15. }
  16. }

(3)配置:

  1. services.AddMvc(……).AddFluentValidation();
  2. services.AddTransient<IValidator<PostAddResource>, PostAddResourceValidator>();

(4)Action添加验证:

ModelState.IsValid
                     ModelState
                           它是一个字典,包含了Model的状态以及Model所绑定的验证
                           对于提交的每个属性,它都包含了一个错误信息的集合
                           返回: 422 Unprocessable Entity
                      验证错误信息在响应的body里面带回去

  1. if (!ModelState.IsValid)
  2. {
  3. return UnprocessableEntity(ModelState);
  4. }

 (5)测试

(6)Action添加Accpet和Content-Type 的自定义hateoas

  1. [RequestHeaderMatchingMediaType("Content-Type", new[] { "application/vnd.cgzl.post.create+json" })]
  2. [RequestHeaderMatchingMediaType("Accept", new[] { "application/vnd.cgzl.hateoas+json" })]

  (7)  staupDevelopment 注册hateoas

  1. services.AddMvc(option => {
  2. option.ReturnHttpNotAcceptable = true;
  3. // option.OutputFormatters.Add(new XmlDataContractSerializerOutputFormatter());
  4. var outputFormatter = option.OutputFormatters.OfType<JsonOutputFormatter>().FirstOrDefault();
  5. if (outputFormatter != null)
  6. {
  7. outputFormatter.SupportedMediaTypes.Add("application/vnd.cgzl.hateoas+json");
  8. }
  9.  
  10. var intputFormatter = option.InputFormatters.OfType<JsonInputFormatter>().FirstOrDefault();
  11. if (intputFormatter != null)
  12. {
  13. intputFormatter.SupportedMediaTypes.Add("application/vnd.cgzl.post.create+json");
  14. intputFormatter.SupportedMediaTypes.Add("application/vnd.cgzl.post.update+json");
  15. }
  16.  
  17. })

(8)测试:

3、自定义错误验证返回结果:

(1) 添加MyUnprocessableEntityObjectResult.cs   ResourceValidationError.cs   ResourceValidationResult.cs 类

  1. namespace BlogDemo.Api.Helpers
  2. {
  3. public class MyUnprocessableEntityObjectResult : UnprocessableEntityObjectResult
  4. {
  5. public MyUnprocessableEntityObjectResult(ModelStateDictionary modelState) : base(new ResourceValidationResult(modelState))
  6. {
  7. if (modelState == null)
  8. {
  9. throw new ArgumentNullException(nameof(modelState));
  10. }
  11. StatusCode = ;
  12. }
  13. }
  14. }
  1. namespace BlogDemo.Api.Helpers
  2. {
  3. public class ResourceValidationError
  4. {
  5. public string ValidatorKey { get; private set; }
  6. public string Message { get; private set; }
  7.  
  8. public ResourceValidationError(string message, string validatorKey = "")
  9. {
  10. ValidatorKey = validatorKey;
  11. Message = message;
  12. }
  13. }
  14. }
  1. namespace BlogDemo.Api.Helpers
  2. {
  3. public class ResourceValidationResult : Dictionary<string, IEnumerable<ResourceValidationError>>
  4. {
  5. public ResourceValidationResult() : base(StringComparer.OrdinalIgnoreCase)
  6. {
  7.  
  8. }
  9.  
  10. public ResourceValidationResult(ModelStateDictionary modelState)
  11. : this()
  12. {
  13. if (modelState == null)
  14. {
  15. throw new ArgumentNullException(nameof(modelState));
  16. }
  17.  
  18. foreach (var keyModelStatePair in modelState)
  19. {
  20. var key = keyModelStatePair.Key;
  21. var errors = keyModelStatePair.Value.Errors;
  22. if (errors != null && errors.Count > )
  23. {
  24. var errorsToAdd = new List<ResourceValidationError>();
  25. foreach (var error in errors)
  26. {
  27. var keyAndMessage = error.ErrorMessage.Split('|');
  28.  
  29. if (keyAndMessage.Length > )
  30. {
  31. errorsToAdd.Add(new ResourceValidationError(keyAndMessage[], keyAndMessage[]));
  32. }
  33. else
  34. {
  35. errorsToAdd.Add(new ResourceValidationError(keyAndMessage[]));
  36. }
  37. }
  38. Add(key, errorsToAdd);
  39. }
  40. }
  41. }
  42. }
  43. }

(2)Action中添加自定义验证:

  1. public async Task<IActionResult> Post([FromBody] PostAddResource postAddResource)
  2. {
  3.  
  4. if (!ModelState.IsValid)
  5. {
  6. return new MyUnprocessableEntityObjectResult(ModelState);
  7. }
  8. }

(3)测试

三、Delete

1、 在PostRepository 添加Delete方法

  1. public void Delete(Post post)
  2. {
  3. _myContext.Posts.Remove(post);
  4. }

2、Action添加Delete方法:

  1. [HttpDelete("{id}", Name = "DeletePost")]
  2. public async Task<IActionResult> DeletePost(int id)
  3. {
  4. var post = await _postRepository.GetPostId(id);
  5. if (post == null)
  6. {
  7. return NotFound();
  8. }
  9.  
  10. _postRepository.Delete(post);
  11.  
  12. if (!await _unitOfWork.SaveAsync())
  13. {
  14. throw new Exception($"Deleting post {id} failed when saving.");
  15. }
  16.  
  17. return NoContent();
  18. }

四、PUT(整体更新)

1、添加PostUpdateResource.cs 类;

  1. public class PostUpdateResource : PostAddOrUpdateResource
  2. {
  3.  
  4. }

2、重构  PostAddOrUpdateResourceValidator.cs ,改成泛型

  1. namespace BlogDemo.Infrastructure.Resources
  2. {
  3. public class PostAddOrUpdateResourceValidator<T> : AbstractValidator<T> where T: PostAddOrUpdateResource
  4. {
  5. public PostAddOrUpdateResourceValidator()
  6. {
  7. RuleFor(x => x.Title).NotEmpty()
  8. .WithName("标题").WithMessage("required|{PropertyName}是必须填写的")
  9. .MaximumLength().WithMessage("maxLength|{PropertyName}的最大长度是{MaxLength}");
  10.  
  11. RuleFor(x => x.Body).NotEmpty()
  12. .WithName("正文").WithMessage("required|{PropertyName}是必须填写的")
  13. .MinimumLength().WithMessage("minLength|{PropertyName}的最小长度是{MinLength}");
  14. }
  15. }
  16. }

3、资源验证注册:

  1. services.AddTransient<IValidator<PostUpdateResource>, PostAddOrUpdateResourceValidator<PostUpdateResource>>();

4、添加Map

  1. namespace BlogDemo.Api.Extensions
  2. {
  3. public class MappingProfile:Profile
  4. {
  5. public MappingProfile()
  6. {
  7. CreateMap<Post, PostDTO>().ForMember(dest=>dest.Updatetime,opt=>opt.MapFrom(src=>src.LastModified));
  8. CreateMap<PostDTO, Post>();
  9. CreateMap<PostAddResource, Post>();
  10. CreateMap<PostUpdateResource, Post>();
  11. }
  12. }
  13. }

5、添加自定义hateoas

  1. public void ConfigureServices(IServiceCollection services)
  2. {
  3. services.AddMvc(option => {
  4. option.ReturnHttpNotAcceptable = true;
  5. // option.OutputFormatters.Add(new XmlDataContractSerializerOutputFormatter());
  6. var outputFormatter = option.OutputFormatters.OfType<JsonOutputFormatter>().FirstOrDefault();
  7. if (outputFormatter != null)
  8. {
  9. outputFormatter.SupportedMediaTypes.Add("application/vnd.cgzl.hateoas+json");
  10. }
  11.  
  12. var intputFormatter = option.InputFormatters.OfType<JsonInputFormatter>().FirstOrDefault();
  13. if (intputFormatter != null)
  14. {
  15. intputFormatter.SupportedMediaTypes.Add("application/vnd.cgzl.post.create+json");
  16. intputFormatter.SupportedMediaTypes.Add("application/vnd.cgzl.post.update+json");
  17. }
  18.  
  19. })
    }

6、Action添加PUT方法:

  1. [HttpPut("{id}", Name = "UpdatePost")]
  2. [RequestHeaderMatchingMediaType("Content-Type", new[] { "application/vnd.cgzl.post.update+json" })]
  3. public async Task<IActionResult> UpdatePost(int id, [FromBody] PostUpdateResource postUpdate)
  4. {
  5. if (postUpdate == null)
  6. {
  7. return BadRequest();
  8. }
  9.  
  10. if (!ModelState.IsValid)
  11. {
  12. return new MyUnprocessableEntityObjectResult(ModelState);
  13. }
  14.  
  15. var post = await _postRepository.GetPostId(id);
  16. if (post == null)
  17. {
  18. return NotFound();
  19. }
  20.  
  21. post.LastModified = DateTime.Now;
  22. _mapper.Map(postUpdate, post);
  23.  
  24. if (!await _unitOfWork.SaveAsync())
  25. {
  26. throw new Exception($"Updating post {id} failed when saving.");
  27. }
  28. return NoContent();
  29. }

7、测试

五、Patch(局部更新)

1、 PostRepository 添加Update方法:

  1. public void Update(Post post)
  2. {
  3. _myContext.Entry(post).State = EntityState.Modified;
  4. }

2、Action添加Patch方法:

  1. [HttpPatch("{id}", Name = "PartiallyUpdatePost")]
  2. public async Task<IActionResult> PartiallyUpdateCityForCountry(int id,
  3. [FromBody] JsonPatchDocument<PostUpdateResource> patchDoc)
  4. {
  5. if (patchDoc == null)
  6. {
  7. return BadRequest();
  8. }
  9.  
  10. var post = await _postRepository.GetPostByIdAsync(id);
  11. if (post == null)
  12. {
  13. return NotFound();
  14. }
  15.  
  16. var postToPatch = _mapper.Map<PostUpdateResource>(post);
  17.  
  18. patchDoc.ApplyTo(postToPatch, ModelState);
  19.  
  20. TryValidateModel(postToPatch);
  21.  
  22. if (!ModelState.IsValid)
  23. {
  24. return new MyUnprocessableEntityObjectResult(ModelState);
  25. }
  26.  
  27. _mapper.Map(postToPatch, post);
  28. post.LastModified = DateTime.Now;
  29. _postRepository.Update(post);
  30.  
  31. if (!await _unitOfWork.SaveAsync())
  32. {
  33. throw new Exception($"Patching city {id} failed when saving.");
  34. }
  35.  
  36. return NoContent();
  37. }

3、测试

六、HTTP常用方法总结

ASP NET Core ---POST, PUT, PATCH, DELETE,Model 验证的更多相关文章

  1. 008.Adding a model to an ASP.NET Core MVC app --【在 asp.net core mvc 中添加一个model (模型)】

    Adding a model to an ASP.NET Core MVC app在 asp.net core mvc 中添加一个model (模型)2017-3-30 8 分钟阅读时长 本文内容1. ...

  2. 创建ASP.NET Core MVC应用程序(6)-添加验证

    创建ASP.NET Core MVC应用程序(6)-添加验证 DRY原则 DRY("Don't Repeat Yourself")是MVC的设计原则之一.ASP.NET MVC鼓励 ...

  3. ASP.NET MVC基于标注特性的Model验证:将ValidationAttribute应用到参数上

    原文:ASP.NET MVC基于标注特性的Model验证:将ValidationAttribute应用到参数上 ASP.NET MVC默认采用基于标准特性的Model验证机制,但是只有应用在Model ...

  4. ASP.NET MVC基于标注特性的Model验证:一个Model,多种验证规则

    原文:ASP.NET MVC基于标注特性的Model验证:一个Model,多种验证规则 对于Model验证,理想的设计应该是场景驱动的,而不是Model(类型)驱动的,也就是对于同一个Model对象, ...

  5. 如何为ASP.NET Core设置客户端IP白名单验证

    原文链接:Client IP safelist for ASP.NET Core 作者:Damien Bowden and Tom Dykstra 译者:Lamond Lu 本篇博文中展示了如何在AS ...

  6. Asp.net Core, 基于 claims 实现权限验证 - 引导篇

    什么是Claims? 这个直接阅读其他大神些的文章吧,解释得更好. 相关文章阅读: http://www.cnblogs.com/JustRun1983/p/4708176.html http://w ...

  7. 【ASP.NET Core】JSON Patch 使用简述

    JSON Patch 是啥玩意儿?不知道,直接翻译吧,就叫它“Json 补丁”吧.干吗用的呢?当然是用来修改 JSON 文档的了.那咋修改呢?比较常见有四大操作:AMRR. 咋解释呢? A—— Add ...

  8. Asp.Net Core 入门(四)—— Model、View、Controller

    和我们学习Asp.Net MVC一样,Asp.Net Core MVC的Model.View.Controller也和我们熟悉的Asp.Net MVC中的相似.不同的是我们在使用Asp.Net Cor ...

  9. ASP.NET Core MVC 之模型(Model)

    1.模型绑定 ASP.NET Core MVC 中的模型绑定将数据从HTTP请求映射到操作方法参数.参数既可以是简单类型,也可以是复杂类型.MVC 通过抽象绑定解决了这个问题. 2.使用模型绑定 当 ...

随机推荐

  1. 10474 - Where is the Marble?(模拟)

    传送门: UVa10474 - Where is the Marble? Raju and Meena love to play with Marbles. They have got a lot o ...

  2. Trident中 FixedBatchSpout分析

    FixedBatchSpout 继承自 IBatchSpout IBatchSpout 方法 public interface IBatchSpout extends Serializable { v ...

  3. LeetCode13.罗马数字转整数 JavaScript

    罗马数字包含以下七种字符: I, V, X, L,C,D 和 M. 字符 数值 I 1 V 5 X 10 L 50 C 100 D 500 M 1000 例如, 罗马数字 2 写做 II ,即为两个并 ...

  4. Linux修改时区以及同步时间

    Centos7为例:修改时区 timedatectl list-timezones |grep Shanghai #查找中国时区的完整名称 Asia/Shanghai timedatectl set- ...

  5. 使用缓存时出现java.io.NotSerializableException:xxx.xxx.xxx.Bean解决办法

    解决方案:   开发过程中如果想缓存某个JavaBean,请确保它所引用的对象都implents Serializable,如果某个对象不需要被cache,可以加上transient关键字,否则Ehc ...

  6. css选择器有哪些

    css的选择器是还是比较富的,主要的css选择器如下: 标签选择器(如:body,div,p,ul,li) .类选择器(如:class="head",class="hea ...

  7. foreach, for in, for of 之间的异同

    forEach() 方法用于调用数组的每个元素,并将元素传递给回调函数. 注意: forEach() 对于空数组是不会执行回调函数的. 示例代码: var arr = [4, 9, 16, 25]; ...

  8. ABAP术语-Business Object Builder

    Business Object Builder 原文:http://www.cnblogs.com/qiangsheng/archive/2008/01/09/1031357.html Tool fo ...

  9. 关于ECharts内存泄漏问题

    最近使用websocket加ECharts做了一个实时监控的功能,发现了一个比较严重的问题,就是浏览器运行一段时间就会非常卡,之前在ECharts官网运行官方实例“动态数据 + 时间坐标轴”时,也遇到 ...

  10. android Volley+Gson的使用

    听说Volley框架非常好用,今天试了一下post请求,果然如此,因为我传的是json获取的也是json所以就写了一种关于json的请求,其实其他的代码都差不多.首先要先创建一个全局的变量,请求入队列 ...