At this stage, basically the front and rear end of the separation project, this way, we need to fit the front and rear ends, there is no uniform return format, docking will be very cumbersome and time consuming. We need to put all the interfaces and exception error message returns a certain Json format, in favor of front-end processing, thereby improving work efficiency.
First, the preparatory work
Responding entity classes defined
/// <Summary> /// response entity class /// </ Summary> public class ResultModel { /// <summary> /// 状态码 /// </summary> public int ReturnCode { get; set; } /// <summary> /// 内容 /// </summary> public object Data { get; set; } /// <Summary> /// error /// </ Summary> public String the ErrorMessage { GET ; SET ;} /// <Summary> /// success /// </ Summary> public BOOL isSuccess { GET ; SET ;} }
Modify Controller layer
The service request processing layer controller, a new new ResultModel object, and returns to the front end.
/// <summary> /// 查询用户 /// </summary> /// <returns></returns> [Route("getUser")] [HttpGet] public ResultModel GetUser() { var data = _userRepository.GetAll().ToList(); return new ResultModel() { Data = data, ErrorMessage = null, IsSuccess = true, ReturnCode = 200 }; }
This requires each method needs to re-new a ResultModel objects, feeling a little code redundancy.
We only need to add a few static methods, each return is ResultModel object when a successful call ResultModel.OK, failed when calling ResultModel.ERROR can be.
optimization
Add two static methods
/// <summary> /// 成功 /// </summary> /// <param name="data">返回数据</param> /// <returns></returns> public static ResultModel Ok(object data) { return new ResultModel { Data = data, ErrorMessage = null, IsSuccess = true, ReturnCode = 200 }; } /// <Summary> /// failed /// </ Summary> /// <param name = "STR"> error </ param> /// <param name = "code"> status code </ param > /// <Returns> </ Returns> public static ResultModel Error ( String STR, int code) { return new ResultModel { Data = null, ErrorMessage = str, IsSuccess = false, ReturnCode = code }; }
Modify the controller
/// <summary> /// 查询用户 /// </summary> /// <returns></returns> [Route("getUser")] [HttpGet] public ResultModel GetUser() { var data = _userRepository.GetAll().ToList(); return ResultModel.Ok(data); }
Second, the global exception handler
By global exception handler, any error messages will be intercepted, returned a unified format.
Define a global exception handler middleware
using System; using System.Threading.Tasks; using Microsoft.AspNetCore.Http; using NetCoreWebApi.Util; using Newtonsoft.Json; namespace NetCoreWebApi.Filter { /// <Summary> /// processing middleware global information /// </ Summary> public class ExceptionMiddleWare { /// <Summary> /// handler HTTP request. /// </ Summary> Private Readonly RequestDelegate -next; /// <Summary> /// Constructor /// </ Summary> /// <param name = "Next"> </ param> public ExceptionMiddleWare (Next RequestDelegate ) { _next = next; } public async Task Invoke(HttpContext context) { try { // throw a next intermediate the await -next (context); } catch (Exception ex) { await WriteExceptionAsync(context, ex); } finally { await WriteExceptionAsync(context, null); } } private async Task WriteExceptionAsync(HttpContext context, Exception exception) { if (exception != null) { var response = context.Response; var message = exception.InnerException == null ? exception.Message : exception.InnerException.Message; response.ContentType = "application/json"; await response.WriteAsync(JsonConvert.SerializeObject(ResultModel.Error(message, 400))).ConfigureAwait(false); } else { var code = context.Response.StatusCode; switch (code) { case 200: return; case 204: return; case 401: context.Response.ContentType = "application/json"; await context.Response.WriteAsync(JsonConvert.SerializeObject(ResultModel.Error("token已过期,请重新登录.", code))).ConfigureAwait(false); break; default: context.Response.ContentType = "application/json"; await context.Response.WriteAsync(JsonConvert.SerializeObject(ResultModel.Error("未知错误", code))).ConfigureAwait(false); break; } } } } }
Registration Middleware
The method of adding the Configure UseMiddleware starting class method Startup.cs
// exception handling intermediate app.UseMiddleware ( typeof (ExceptionMiddleWare));
Third, the solid model verification
There are two ways:
1. Use custom filter
2. The default model validation 400 comes need to add [ApiController] In the above controller, higher priority in this way, if the need to customize the model validation, the need to close the default model validation
【ApiController】
Binding parameters automatically inferred: may be omitted [FromBody] characteristic parameters
Automatic model verification: Automatic verification model is legitimate
Reference: https://blog.csdn.net/sD7O95O/article/details/81844154
services.AddMvc(e => { e.Filters.Add<CheckModel>(); }) .SetCompatibilityVersion(CompatibilityVersion.Version_2_2) .ConfigureApiBehaviorOptions(e => { // Close the default model validation e.SuppressModelStateInvalidFilter = to true ; });
Custom filter
Creating CheckModel filter ActionFilterAttribute inherit the abstract class, method, which requires rewriting
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.Filters; using NetCoreWebApi.Util; namespace NetCoreWebApi.Filter { /// <the Summary> /// verify legal entity objects /// </ the Summary> public class CheckModel: ActionFilterAttribute { /// <summary> /// Action 调用前执行 /// </summary> /// <param name="actionContext"></param> public override void OnActionExecuting(ActionExecutingContext actionContext) { if (!actionContext.ModelState.IsValid) { // initialize result returned var Result = new new ResultModel = {isSuccess to false , the ReturnCode = 400 }; the foreach ( var Item in actionContext.ModelState.Values) { foreach (var error in item.Errors) { result.ErrorMessage += error.ErrorMessage + "|"; } } actionContext.Result = new BadRequestObjectResult(result); } } /// <Summary> /// the method calls Action, Result before calling the execution method /// </ Summary> /// <param name = "context"> </ param> public the override void the OnActionExecuted (ActionExecutedContext context) {
} } }
The write filter is registered to Global
services.AddMvc(e => { // Register filter e.Filters.Add <CheckModel> (); }) .SetCompatibilityVersion(CompatibilityVersion.Version_2_2) .ConfigureApiBehaviorOptions(e => { // Close the default model validation e.SuppressModelStateInvalidFilter = to true ; });
Creating UserDto
using System.ComponentModel.DataAnnotations; namespace NetCoreWebApi.Repository.Dto { /// <Summary> /// user transfer object /// </ Summary> public class UserDTO { /// <Summary> /// user Id /// </ Summary> [the StringLength ( 32 , the ErrorMessage = " {1} {0} most characters " ), Display (the Name = " User Id " )] public String {the UserId GET ; SET ;} /// <Summary> /// username /// </ Summary> [the StringLength ( 20 is , the ErrorMessage = " {1} {0} most characters " ), Display (the name = " username ")] public String UserName { GET ; SET ;} /// <Summary> /// Mailbox /// </ Summary> [the StringLength ( 30 , the ErrorMessage = " {1} {0} most characters " ), Display (the Name = " mailbox " )] public String In email { GET ; SET ;} } }
test
The default model validation
services.AddMvc(e => { // Register filter e.Filters.Add <CheckModel> (); }) .SetCompatibilityVersion(CompatibilityVersion.Version_2_2) .ConfigureApiBehaviorOptions(e => { /// / off default model validation // e.SuppressModelStateInvalidFilter = to true; e.InvalidModelStateResponseFactory ActionContext = => { // get a verification failure model field var errors = actionContext.ModelState .Where(e1 => e1.Value.Errors.Count > 0) .Select(e1 => e1.Value.Errors.First().ErrorMessage) .ToList(); var str = string.Join("|", errors); return new BadRequestObjectResult(ResultModel.Error(str, 400)); }; });
Two methods of verification are consistent effect