环境 .Net 7.0 项目 ASP.NET Core WebAPI

筛选器、过滤器、拦截器介绍

ASP.NET Core 中的筛选器

请求管道

创建统一返回值基类

public class BaseResultModel
{
    public int? Code { get; set; }

    public string Message { get; set; }

    public object? Data { get; set; }

    public int ReturnStatus { get; set; }
}

拦截特性验证过滤器

IActionFilter 接口

编号方法说明
1OnActionExecuted(ActionExecutedContext))在操作执行后调用,然后执行操作结果。
2OnActionExecuting(ActionExecutingContext))在操作执行之前调用,模型绑定完成后。

自定义验证过滤器

/// <summary>
/// 验证过滤器
/// </summary>
public class MyValidationFilterAttribute : IActionFilter
{
    public void OnActionExecuting(ActionExecutingContext context)
    {
        if (!context.ModelState.IsValid) // 是否通过验证
        {
            var result = context.ModelState.Keys
                .SelectMany(key => context.ModelState[key]!.Errors.Select(x => new ValidationError(key, x.ErrorMessage)))
                .ToList();
            context.Result = new ObjectResult(new BaseResultModel
            {
                Code = 400,
                Message = "error",
                Data = result,
                ReturnStatus = 0
            });
        }
    }

    public void OnActionExecuted(ActionExecutedContext context)
    {
        // throw new NotImplementedException();
    }
}

添加过滤器

添加过滤器

解除默认限制

builder.Services.Configure<ApiBehaviorOptions>(options =>
{
    options.SuppressModelStateInvalidFilter = true;
});

创建业务

// Person类用于接口请求数据
public class Person
{
    [Range(1,10,ErrorMessage = "范围1-10")]
    public int Age { get; set; }

    [MinLength(2,ErrorMessage = "名称不能低于2个字符")]
    public string Name { get; set; } = String.Empty;
}

// API接口
[HttpPost]
public Person AddPerson(Person input)
{
    return input;
}

事例

未通过特性验证

验证失败事例

验证成功事例

拦截异常过滤器

IExceptionFilter 接口

编号方法说明
1OnException(ExceptionContext))在操作引发后 Exception调用

自定义异常过滤器

/// <summary>
/// 异常过滤器
/// </summary>
public class MyExceptionFilterAttribute : IExceptionFilter
{
    public void OnException(ExceptionContext context)
    {
        var exception = context.Exception;
        context.ExceptionHandled = true;
        context.Result = new ObjectResult(new BaseResultModel()
        {
            Code = 400,
            Message = exception.InnerException != null ? exception.InnerException.Message : exception.Message,
            Data = exception.Message, // 可改为其他值
            ReturnStatus = 3
        });
    }
}

创建业务

[HttpGet]
public void ThrowException()
{
    throw new Exception("抛出了一个异常");
}

添加过滤器

添加异常拦截过滤器

事例

拦截异常

验证异常拦截

操作筛选器

IActionFilter 接口

编号方法说明
1OnActionExecuted(ActionExecutedContext))在操作执行后调用,然后执行操作结果。
2OnActionExecuting(ActionExecutingContext))在操作执行之前调用,模型绑定完成后。

自定义操作筛选器

/// <summary>
/// 操作拦截器
/// </summary>
public class MyActionFilterAttribute : IActionFilter
{
    public void OnActionExecuting(ActionExecutingContext context)
    {
        // throw new NotImplementedException();
    }

    public void OnActionExecuted(ActionExecutedContext context)
    {
        var result = context.Result as ObjectResult;
        context.Result = new OkObjectResult(new BaseResultModel
        {
            Code = 200,
            Message = "success",
            Data = result?.Value,
            ReturnStatus = 1
        });
    }
}

创建业务

[HttpPost]
public DateTime GetNowTime()
{
    return DateTime.Now;
}

添加过滤器

添加过滤器

事例

请求成功

使用拦截器统一返回值,将三个过滤器添加到配置中

builder.Services.AddMvc(options =>
{
    options.Filters.Add<MyActionFilterAttribute>();
    options.Filters.Add<MyExceptionFilterAttribute>();
    options.Filters.Add<MyValidationFilterAttribute>();
});

优化

原因

由于【特性拦截器】和【操作拦截器】都继承了IActionFilter接口,但拦截位置不同所以会出现异常信息包含在操作拦截器内(套娃现象),所以要修改两个拦截器内逻辑

套娃

解决一

取消特性验证拦截器,在操作拦截器内进行验证判断
/// <summary>
/// 操作拦截器
/// </summary>
public class MyActionFilterAttribute : IActionFilter
{
    public void OnActionExecuting(ActionExecutingContext context)
    {
        // throw new NotImplementedException();
    }

    public void OnActionExecuted(ActionExecutedContext context)
    {
        if (!context.ModelState.IsValid)
        {
            var result = context.ModelState.Keys
                .SelectMany(key => context.ModelState[key]!.Errors.Select(x => new ValidationError(key, x.ErrorMessage)))
                .ToList();
            context.Result = new ObjectResult(new BaseResultModel
            {
                Code = 400,
                Message = "error",
                Data = result,
                ReturnStatus = ReturnStatus.Fail
            });
        }
        else
        {
            var statusCode = HttpStatusCode.OK;
            var result = context.Result as ObjectResult;
            context.Result = new OkObjectResult(new BaseResultModel
            {
                Code = (int)statusCode,
                Message = "success",
                Data = result?.Value,
                ReturnStatus = ReturnStatus.Success
            });
        }
    }
}

解决二

/// <summary>
/// 操作拦截器
/// </summary>
public class MyActionFilterAttribute : IActionFilter
{
    public void OnActionExecuting(ActionExecutingContext context)
    {
        if (!context.ModelState.IsValid)
        {
            var result = context.ModelState.Keys
                .SelectMany(
                    key => context.ModelState[key]!.Errors.Select(x => new ValidationError(key, x.ErrorMessage)))
                .ToList();
            context.Result = new ObjectResult(new BaseResultModel
            {
                Code = 400,
                Message = "error",
                Data = result,
                ReturnStatus = ReturnStatus.Fail
            });
        }
    }

    public void OnActionExecuted(ActionExecutedContext context)
    {
        var statusCode = HttpStatusCode.OK;
        var result = context.Result as ObjectResult;
        context.Result = new OkObjectResult(new BaseResultModel
        {
            Code = (int)statusCode,
            Message = "success",
            Data = result?.Value,
            ReturnStatus = ReturnStatus.Success
        });
    }
}

完整代码

/// <summary>
/// 异常过滤器
/// </summary>
public class MyExceptionFilterAttribute : IExceptionFilter
{
    public void OnException(ExceptionContext context)
    {
        var exception = context.Exception;
        context.ExceptionHandled = true;
        context.Result = new ObjectResult(new BaseResultModel()
        {
            Code = 400,
            Message = exception.InnerException != null ? exception.InnerException.Message : exception.Message,
            Data = exception.Message,
            ReturnStatus = ReturnStatus.Error
        });
    }
}

/// <summary>
/// 操作拦截器/特性拦截器
/// </summary>
public class MyActionFilterAttribute : IActionFilter
{
    public void OnActionExecuting(ActionExecutingContext context)
    {
        if (!context.ModelState.IsValid)
        {
            var result = context.ModelState.Keys
                .SelectMany(
                    key => context.ModelState[key]!.Errors.Select(x => new ValidationError(key, x.ErrorMessage)))
                .ToList();
            context.Result = new ObjectResult(new BaseResultModel
            {
                Code = 400,
                Message = "error",
                Data = result,
                ReturnStatus = ReturnStatus.Fail
            });
        }
    }

    public void OnActionExecuted(ActionExecutedContext context)
    {
        var statusCode = HttpStatusCode.OK;
        var result = context.Result as ObjectResult;
        context.Result = new OkObjectResult(new BaseResultModel
        {
            Code = (int)statusCode,
            Message = "success",
            Data = result?.Value,
            ReturnStatus = ReturnStatus.Success
        });
    }
}
最后修改:2023 年 02 月 22 日
如果觉得我的文章对你有用,请随意赞赏