ASP.NET Core 2.2 WebApi series [8] unified format return (the return value, model validation, exception)

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

Reference: https://docs.microsoft.com/zh-cn/dotnet/api/microsoft.aspnetcore.mvc.apibehavioroptions?view=aspnetcore-2.2

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

Guess you like

Origin www.cnblogs.com/tenghao510/p/11927930.html