ASP.NET CORE 6.0实现Filter过滤器

一、什么是Filter

ASP.NET Core 中,Filter 是一种用于处理 HTTP 请求和响应的机制,它可以让你在请求和响应的不同阶段添加额外的逻辑。Filter 在 MVC(Model-View-Controller)和 Web API 应用程序中起着重要作用,可以帮助你实现诸如身份验证、授权、日志记录、异常处理等功能。

二、 创建自定义的 Action Filter
    /// <summary>
    /// 自定义的 Action Filter,用于在动作方法执行前后记录日志
    /// </summary>
    public class CustomActionFilter : ActionFilterAttribute
    {
        private static readonly ILog log = LogManager.GetLogger(typeof(CustomActionFilter));

        /// <summary>
        /// Id
        /// </summary>
        private string SysId { get; set; }

        /// <summary>
        /// 密钥
        /// </summary>
        private string SysSecret { get; set; }

        /// <summary>
        /// 构造函数,接收系统Id和密钥
        /// </summary>
        /// <param name="sysId"></param>
        /// <param name="sysSecret"></param>
        public CustomActionFilter(string sysId, string sysSecret)
        {
            this.SysId = sysId;
            this.SysSecret = sysSecret;
        }

        /// <summary>
        /// Action执行前的逻辑
        /// </summary>
        /// <param name="context"></param>
        /// <param name="next"></param>
        /// <returns></returns>
        public override async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
        {
            log.Info("Action执行前...");
            var request = context.HttpContext.Request;
            string sysId = GetRequestValue(context, SysId);
            string sysSecret = GetRequestValue(context, SysSecret);
            if (string.IsNullOrEmpty(sysId) || string.IsNullOrEmpty(sysSecret))
            {
                //context.Result = new UnauthorizedObjectResult("签名无效!");
                //return;
            }

            #region sysId 和 sysSecret 都不为空的情况下执行的操作(建议这存储到数据库)

            // 执行并记录日志
            FilterLog filterLog = new FilterLog()
            {
                Name = context.Controller.GetType().Name,
                RequestUrl = GetUrl(request),
                RequestMethod = request.Method,
                RequestBody = await GetBodyAsStringAsync(request),
                RequestTime = DateTime.Now,
                RequestIpAddress = context.HttpContext.Connection.RemoteIpAddress?.ToString(),
            };
            string json = JsonConvert.SerializeObject(filterLog);
            log.Info($"日志: {json}");

            #endregion

            await next();
        }

        /// <summary>
        /// Action执行后的逻辑
        /// </summary>
        /// <param name="context"></param>
        /// <param name="next"></param>
        /// <returns></returns>
        public override async Task OnResultExecutionAsync(ResultExecutingContext context, ResultExecutionDelegate next)
        {
            log.Info("Action执行后...");
            await next();
        }

        /// <summary>
        /// 获取请求参数的值
        /// </summary>
        /// <param name="actionContext"></param>
        /// <param name="paramName"></param>
        /// <returns></returns>
        private string GetRequestValue(ActionExecutingContext actionContext, string paramName)
        {
            HttpRequest request = actionContext.HttpContext.Request;
            if (request == null)
                return null;

            if (request.ContentType != null && request.ContentType.IndexOf("multipart/form-data", StringComparison.OrdinalIgnoreCase) >= 0)
            {
                return null;
            }

            foreach (object value in actionContext.ActionArguments.Values)
            {
                var dict = JObject.Parse(JsonConvert.SerializeObject(value));
                if (dict != null && dict.ContainsKey(paramName))
                    return dict[paramName].ToString();
            }

            return null;
        }

        /// <summary>
        /// 获取请求的URL
        /// </summary>
        /// <param name="httpRequest"></param>
        /// <returns></returns>
        private static string GetUrl(HttpRequest httpRequest)
        {
            StringBuilder builder = new StringBuilder();

            if (!string.IsNullOrWhiteSpace(httpRequest.Scheme))
            {
                builder.Append(httpRequest.Scheme);
                builder.Append("://");
            }

            builder.Append(httpRequest.Host.ToUriComponent());
            builder.Append(httpRequest.PathBase.ToUriComponent());
            builder.Append(httpRequest.Path.ToUriComponent());
            builder.Append(httpRequest.QueryString.ToUriComponent());

            return builder.ToString();
        }

        /// <summary>
        /// 异步获取请求主体的内容
        /// </summary>
        /// <param name="httpRequest"></param>
        /// <returns></returns>
        public static async Task<string> GetBodyAsStringAsync(HttpRequest httpRequest)
        {
            if (httpRequest.Body == null)
            {
                return null;
            }

            if (!httpRequest.Body.CanSeek)
            {
                httpRequest.EnableBuffering();
            }

            var currentPosition = httpRequest.Body.Position;

            httpRequest.Body.Position = 0;

            string requestBody;
            using (var reader = new StreamReader(httpRequest.Body, leaveOpen: true))
            {
                requestBody = await reader.ReadToEndAsync();
            }

            httpRequest.Body.Position = currentPosition;

            return requestBody;
        }
    }

 三、 为控制器或动作方法应用过滤器加上[CustomActionFilter("sysId", "sysSecret")]

接口就是简单EF core的增删改查

using AutoMapper;
using Microsoft.AspNetCore.Mvc;
using TodoApiCore6._0.Tools.Context;
using TodoApiCore6._0.Models;
using TodoApiCore6._0.Models.DTO;
using Microsoft.EntityFrameworkCore;
using TodoApiCore6._0.Models.ApiResult;
using Microsoft.Data.SqlClient;
using TodoApiCore6._0.Tools.Filter;

namespace TodoApiCore6._0.Controllers
{
    [ApiController]
    [Route("[controller]")]
    [CustomActionFilter("sysId", "sysSecret")]
    public class TodoController : Controller
    {
        private readonly TodoContext _context;

        private readonly IMapper _mapper;

        public TodoController(TodoContext context, IMapper mapper, IHttpContextAccessor accessor)
        {
            _context = context;
            _mapper = mapper;
            if (_context.TodoItems.Count() == 0)
            {
                // 如果集合为空,则创建新的 TodoItem, 
                _context.TodoItems.Add(new TodoItem { Name = "Item1", IsComplete = false });
                _context.TodoItems.Add(new TodoItem { Name = "Item2", IsComplete = false });
                _context.TodoItems.Add(new TodoItem { Name = "Item3", IsComplete = true });
                _context.SaveChanges();
            }
            accessor.HttpContext.Request.EnableBuffering();
        }

        /// <summary>
        /// 查询所有列表
        /// </summary>
        /// <returns></returns>
        [HttpGet]
        [Route("All")]
        public async Task<ActionResult<ApiResult>> GetAll()
        {
            //int id = Convert.ToInt32(this.User.FindFirst("Id").Value);
            return ApiResultHelper.Success(await _context.TodoItems.ToArrayAsync());
        }

        /// <summary>
        /// 分页查询
        /// </summary>
        /// <param name="baseQuery"></param>
        /// <returns></returns>
        [HttpGet]
        public async Task<ActionResult<ApiResult>> GetPagination([FromQuery] BaseQuery baseQuery)
        {
            #region 方式一(一次性加载全部数据并进行分页查询可能会导致性能问题)
            //IEnumerable<TodoItem> list = await _context.TodoItems.ToArrayAsync();

            //if (baseQuery.Key == null)
            //{
            //    return ApiResultHelper.Success(list.OrderByDescending(o => o.Id).Distinct().Skip((baseQuery.Page - 1) * baseQuery.Size).Take(baseQuery.Size), list.Count());
            //}

            //return ApiResultHelper.Success(list.Where(o => o.Name.Contains(baseQuery.Key)).OrderByDescending(o => o.Id).Distinct().Skip((baseQuery.Page - 1) * baseQuery.Size).Take(baseQuery.Size), list.Count());
            #endregion

            #region 方式二(推荐使用数据库的分页查询功能)
            string query = "SELECT * FROM TodoItems";

            if (baseQuery.Key != null)
            {
                query += " WHERE Name LIKE '%' + @Keyword + '%'";
            }

            query += " ORDER BY Id DESC OFFSET @Offset ROWS FETCH NEXT @PageSize ROWS ONLY";

            var parameters = new List<SqlParameter>
            {
                new SqlParameter("@Offset", (baseQuery.Page - 1) * baseQuery.Size),
                new SqlParameter("@PageSize", baseQuery.Size)
            };

            if (baseQuery.Key != null)
            {
                parameters.Add(new SqlParameter("@Keyword", baseQuery.Key));
            }

            var currentData = await _context.TodoItems.FromSqlRaw(query, parameters.ToArray()).ToListAsync();
            int currentDataCount = currentData.Count();

            return ApiResultHelper.Success(currentData, currentDataCount);
            #endregion
        }

        /// <summary>
        /// 根据Id查找数据
        /// </summary>
        /// <param name="id">序号</param>
        /// <returns></returns>
        [HttpGet("{id}")]
        public async Task<ActionResult<ApiResult>> GetByID(int id)
        {
            var item = await _context.TodoItems.FirstOrDefaultAsync(t => t.Id == id);
            var todoItemDTO = _mapper.Map<TodoItemDto>(item);
            return ApiResultHelper.Success(todoItemDTO);
        }

        /// <summary>
        /// 创建
        /// </summary>
        /// <param name="item"></param>
        /// <returns></returns>
        [HttpPost]
        public async Task<ActionResult<ApiResult>> Create([FromBody] TodoItem item)
        {
            if (item == null)
            {
                return BadRequest();
            }
            else
            {
                _context.TodoItems.Add(item);
                await _context.SaveChangesAsync();
                return ApiResultHelper.Success(item);
            }
        }

        /// <summary>
        /// 修改
        /// </summary>
        /// <param name="id"></param>
        /// <param name="item"></param>
        /// <returns></returns>
        [HttpPut("{id}")]
        public async Task<ActionResult<ApiResult>> Update([FromBody] TodoItem item)
        {
            HttpContext.Request.EnableBuffering();
            if (item == null)
            {
                return BadRequest();
            }
            else
            {
                var todo = _context.TodoItems.SingleOrDefault(t => t.Id == item.Id);

                if (todo == null)
                {
                    return NotFound();
                }
                else
                {
                    todo.IsComplete = item.IsComplete;
                    todo.Name = item.Name;

                    _context.TodoItems.Update(todo);
                    await _context.SaveChangesAsync();

                    return ApiResultHelper.Success(todo);
                }
            }
        }

        /// <summary>
        /// 删除
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        [HttpDelete("{id}")]
        public async Task<ActionResult<ApiResult>> Delete(int id)
        {
            var todo = _context.TodoItems.SingleOrDefault(t => t.Id == id);

            if (todo == null)
            {
                return NotFound();
            }
            else
            {
                _context.TodoItems.Remove(todo);
                await _context.SaveChangesAsync();

                return ApiResultHelper.Success(todo);
            }
        }
    }
}
// 在Program.cs如下代码,如果不添加获取不到RequestBody内容

#region 添加HttpContextAccessor到服务容器中
builder.Services.AddHttpContextAccessor();
#endregion

四、 日志效果

  • 9
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值