ASP.NET Core Filter

目录

什么是Filter?

Exception Filter

实现

注意

ActionFilter

注意

案例:自动启用事务的筛选器

事务的使用

TransactionScopeFilter的使用


什么是Filter?

  1. 切面编程机制,在ASP.NET Core特定的位置执行我们自定义的代码。
  2. ASP.NET Core中的Filter的五种类型:Authorization filter、Resource filter、Action filter、Exception filter、Result filter。本书中重点讲解Exception filter和Action filter。
  3. 所有筛选器一般有同步和异步两个版本,比如IActionFilter、IAsyncActionFilter接口。

Exception Filter

当系统中出现未经处理的异常的时候,异常筛选器就会执行。

实现

  1. 当系统中出现未处理异常的时候,我们需要统一给客户端返回如下格式的响应报文:{“code”:”500”,”message”:”异常信息”}。
    对于开发环境中message是异常堆栈,对于其他环境message用一个general的报错信息。
  2. 实现IAsyncExceptionFilter接口。注入IHostEnvironment得知运行环境。
public class LogExceptionFilter : IAsyncExceptionFilter
{
    public Task OnExceptionAsync(ExceptionContext context)
    {
        return File.AppendAllTextAsync("F:/error.log", context.Exception.ToString());
    }
}

public class MyExceptionFilter : IAsyncExceptionFilter
{
    private readonly IWebHostEnvironment hostEnv;

    public MyExceptionFilter(IWebHostEnvironment hostEnv)
    {
        this.hostEnv = hostEnv;
    }

    public Task OnExceptionAsync(ExceptionContext context)
    {
        //context.Exception代表异常信息对象
        //context.ExceptionHandled为true时,表示异常已经被处理,其他ExceptionFilter将不会再处理
        //context.Result的值会返回给客户端
        string msg;
        if (hostEnv.IsDevelopment())
        {
            msg = context.Exception.Message;
        }
        else
        {
            msg = "服务器发生了未处理异常";
        }
        ObjectResult objresult = new ObjectResult(new { code = 500, message = msg });
        context.Result = objresult;
        context.ExceptionHandled = true;
        return Task.CompletedTask;
    }
}

注意

ExceptionFilter执行顺序与注册顺序有关,后注册的先执行

builder.Services.Configure<MvcOptions>(opt =>
{
    opt.Filters.Add<MyExceptionFilter>();
    opt.Filters.Add<LogExceptionFilter>();
});

ActionFilter

IAsyncActionFilter接口

多个Action Filter的链式执行。

注意

ActionFilter执行顺序与注册顺序有关,先注册的先执行

public class MyActionFilter1 : IAsyncActionFilter
{
    public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
    {
        Console.WriteLine("MyActionFilter1前代码");
        ActionExecutedContext result = await next();
        if (result.Exception != null)
        {
            Console.WriteLine("MyActionFilter1捕获到异常");
        }
        else
        {
            Console.WriteLine("MyActionFilter1后代码");
        }
    }
}
builder.Services.Configure<MvcOptions>(opt =>
{
    opt.Filters.Add<MyActionFilter1>();
    opt.Filters.Add<MyActionFilter2>();
});

案例:自动启用事务的筛选器

  1. 数据库事务:要么全部成功、要么全部失败。
  2. 自动化:启动、提交以及回滚事务。
  3. 当一段使用EF Core进行数据库操作的代码放到TransactionScope声明的范围中的时候,这段代码就会自动被标记为“支持事务”。
  4. TransactionScope实现了IDisposable接口,如果一个TransactionScope的对象没有调用Complete()就执行了Dispose()方法,则事务会被回滚,否则事务就会被提交。
  5. TransactionScope还支持嵌套式事务。
  6. .NET Core中的TransactionScope不像.NET FX一样有MSDTC分布式事务提升的问题。请使用最终一致性事务。

事务的使用

[HttpPost]
public async Task<string> Test2()
{
    using (TransactionScope tx = new TransactionScope(TransactionScopeAsyncFlowOption.Enabled))
    {
        dbctx.Books.Add(new Book { Title = "计算机网络", Price = 12.6 });
        await dbctx.SaveChangesAsync();
        dbctx.People.Add(new Person { Name = "张三", Age = 20 });
        await dbctx.SaveChangesAsync();
        tx.Complete();
        return "OK";
    }
}

[HttpPost]
public string Test1()
{
    using (TransactionScope tx = new TransactionScope())
    {
        dbctx.Books.Add(new Book { Title = "计算机网络", Price = 12.6 });
        dbctx.SaveChangesAsync();
        dbctx.People.Add(new Person { Name = "张三", Age = 20 });
        dbctx.SaveChangesAsync();
        tx.Complete();
        return "OK";
    }
}

TransactionScopeFilter的使用

对于强制不进行事务控制的Action方法,请标注NotTransactionalAttribute。

开发筛选器TransactionScopeFilter;把TransactionScopeFilter注册到Program.cs中。

NotTransationAttribute.cs:
[AttributeUsage(AttributeTargets.Method)]
public class NotTransationAttribute:Attribute
{
}

TransactionScopeFilter.cs:
public class TransactionScopeFilter : IAsyncActionFilter
{
    public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
    {
        //context.ActionDescriptor中是当前被执行的Action的描述信息
        //context.ActionArguments中是当前被执行的Action的参数信息
        ControllerActionDescriptor controllerActionDescriptor = context.ActionDescriptor as ControllerActionDescriptor;
        //if (controllerActionDescriptor == null)//不是一个MVC的Action
        bool isTX = false;//是否进行事务控制
        if (controllerActionDescriptor != null)
        {
            //获取当前Action是否有NotTransationAttribute特性
            bool hasNotTransationAttribute = controllerActionDescriptor.MethodInfo.GetCustomAttributes(typeof(NotTransationAttribute), false).Any();
            //如果没有NotTransationAttribute特性,则进行事务控制
            isTX = !hasNotTransationAttribute;
        }
        if (isTX)
        {
            //创建一个异步的事务范围
            using (TransactionScope tx=new TransactionScope(TransactionScopeAsyncFlowOption.Enabled))
            {
                var r= await next();
                if (r.Exception==null)
                {
                    tx.Complete();
                }
            }
        }
        else
        {
            await next();
        }
    }
}

Program.cs:
builder.Services.Configure<MvcOptions>(opt =>
{
    opt.Filters.Add<TransactionScopeFilter>();
});

 案例:开发请求限流器

需求

  1. Action Filter可以在满足条件的时候终止操作方法的执行。
  2. 在Action Filter中,如果我们不调用await next(),就可以终止Action方法的执行了。
  3. 为了避免恶意客户端频繁发送大量请求消耗服务器资源,我们要实现“一秒钟内只允许最多有一个来自同一个IP地址的请求”。
public class ratelimitActionFilter : IAsyncActionFilter
{
    private readonly IMemoryCache memcache;

    public ratelimitActionFilter(IMemoryCache memcache)
    {
        this.memcache = memcache;
    }

    public Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
    {
        //从HTTP请求的上下文中获取客户端的远程IP地址
        string removeIP = context.HttpContext.Connection.RemoteIpAddress.ToString();
        //context.ActionDescriptor中是当前被执行的Action的描述信息,转换为ControllerActionDescriptor类型
        ControllerActionDescriptor controllerActionDescriptor = context.ActionDescriptor as ControllerActionDescriptor;
        //构建缓存的Key
        string cacheKey = $"LastVisitTick_{controllerActionDescriptor.ControllerName}_{removeIP}";
        //从缓存中获取上次访问的时间戳
        long? lastTick = memcache.Get<long?>(cacheKey);
        //如果上次访问的时间戳不存在或者距离当前时间已经超过1秒
        if (lastTick == null || Environment.TickCount64 - lastTick > 1000)
        {
            //设置当前的时间戳到缓存中
            memcache.Set(cacheKey, Environment.TickCount64, TimeSpan.FromSeconds(10));//避免长期不访问的用户一直占用缓存
            return next();
        }
        else
        {
            context.Result = new ContentResult
            {
                StatusCode = 429,
                Content = "访问太频繁,请稍后再试!"
            };
            return Task.CompletedTask;
        }
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/964162.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

OpenGL学习笔记(六):Transformations 变换(变换矩阵、坐标系统、GLM库应用)

文章目录 向量变换使用GLM变换&#xff08;缩放、旋转、位移&#xff09;将变换矩阵传递给着色器坐标系统与MVP矩阵三维变换绘制3D立方体 & 深度测试&#xff08;Z-buffer&#xff09;练习1——更多立方体 现在我们已经知道了如何创建一个物体、着色、加入纹理。但它们都还…

麦芯(MachCore)应用开发教程5 --- 工位和晶圆传输

麦芯是构建在windows系统上的设备应用操作系统&#xff0c;利用该系统可以快速高效的开发一款设备专用软件。希望进一步了解请email: acloud163.com 黄国强 2025/02/03 一、工位与子设备的关系 想象工厂中的流水线工作站&#xff0c;每个工位&#xff08;Station&#xff09…

冰蝎v3.0 beta7来啦

我用了一台kali&#xff0c;一台centos&#xff0c;一台windows&#xff0c;做了一个文件上传和一个反弹shell实验&#xff0c;载荷是AES加密的&#xff0c;终于感受到了对加密流量的无可奈何~ kali&#xff08;php8.1&#xff09;centos&#xff08;php7.1&#xff09;window…

Golang 并发机制-5:详解syn包同步原语

并发性是现代软件开发的一个基本方面&#xff0c;Go&#xff08;也称为Golang&#xff09;为并发编程提供了一组健壮的工具。Go语言中用于管理并发性的重要包之一是“sync”包。在本文中&#xff0c;我们将概述“sync”包&#xff0c;并深入研究其最重要的同步原语之一&#xf…

【PyQt】超级超级笨的pyqt计算器案例

计算器 1.QT Designer设计外观 1.pushButton2.textEdit3.groupBox4.布局设计 2.加载ui文件 导入模块&#xff1a; sys&#xff1a;用于处理命令行参数。 QApplication&#xff1a;PyQt5 应用程序类。 QWidget&#xff1a;窗口基类。 uic&#xff1a;用于加载 .ui 文件。…

Flutter Scaffold 页面结构

Material是一套设计风格&#xff0c;提供了大量的小部件&#xff0c;这里用Material风格搭建一个常见的应用页面结构。 创建Material应用 import package:flutter/material.dart;class App extends StatelessWidget {overrideWidget build(BuildContext context) {return Mat…

2月3日星期一今日早报简报微语报早读

2月3日星期一&#xff0c;农历正月初六&#xff0c;早报#微语早读。 1、多个景区发布公告&#xff1a;售票数量已达上限&#xff0c;请游客合理安排行程&#xff1b; 2、2025春节档总票房破70亿&#xff0c;《哪吒之魔童闹海》破31亿&#xff1b; 3、美宣布对中国商品加征10…

大模型本地化部署(Ollama + Open-WebUI)

文章目录 环境准备下载Ollama模型下载下载Open-WebUI 本地化部署的Web图形化界面本地模型联网查询安装 Docker安装 SearXNG本地模型联网查询 环境准备 下载Ollama 下载地址&#xff1a;Ollama网址 安装完成后&#xff0c;命令行里执行命令 ollama -v查看是否安装成功。安装成…

10 Flink CDC

10 Flink CDC 1. CDC是什么2. CDC 的种类3. 传统CDC与Flink CDC对比4. Flink-CDC 案例5. Flink SQL 方式的案例 1. CDC是什么 CDC 是 Change Data Capture&#xff08;变更数据获取&#xff09;的简称。核心思想是&#xff0c;监测并捕获数据库的变动&#xff08;包括数据或数…

【25考研】南开软件考研复试复习重点!

一、复试内容 复试采取现场复试的方式。复试分为笔试、机试和面试三部分。三部分合计100分&#xff0c;其中笔试成绩占30%、机试成绩占30%、面试成绩占40%。 1.笔试&#xff1a;专业综合基础测试 考核方式&#xff1a;闭卷考试&#xff0c;时长为90分钟。 笔试考查内容范围…

【Cadence仿真技巧学习笔记】求解65nm库晶体管参数un, e0, Cox

在设计放大器的第一步就是确定好晶体管参数和直流工作点的选取。通过阅读文献&#xff0c;我了解到L波段低噪声放大器的mos器件最优宽度计算公式为 W o p t . p 3 2 1 ω L C o x R s Q s p W_{opt.p}\frac{3}{2}\frac{1}{\omega LC_{ox}R_{s}Q_{sp}} Wopt.p​23​ωLCox​Rs…

【leetcode练习·二叉树拓展】归并排序详解及应用

本文参考labuladong算法笔记[拓展&#xff1a;归并排序详解及应用 | labuladong 的算法笔记] “归并排序就是二叉树的后序遍历”——labuladong 就说归并排序吧&#xff0c;如果给你看代码&#xff0c;让你脑补一下归并排序的过程&#xff0c;你脑子里会出现什么场景&#xff…

[ESP32:Vscode+PlatformIO]新建工程 常用配置与设置

2025-1-29 一、新建工程 选择一个要创建工程文件夹的地方&#xff0c;在空白处鼠标右键选择通过Code打开 打开Vscode&#xff0c;点击platformIO图标&#xff0c;选择PIO Home下的open&#xff0c;最后点击new project 按照下图进行设置 第一个是工程文件夹的名称 第二个是…

Docker 部署教程jenkins

Docker 部署 jenkins 教程 Jenkins 官方网站 Jenkins 是一个开源的自动化服务器&#xff0c;主要用于持续集成&#xff08;CI&#xff09;和持续交付&#xff08;CD&#xff09;过程。它帮助开发人员自动化构建、测试和部署应用程序&#xff0c;显著提高软件开发的效率和质量…

MySQL锁类型(详解)

锁的分类图&#xff0c;如下&#xff1a; 锁操作类型划分 读锁 : 也称为共享锁 、英文用S表示。针对同一份数据&#xff0c;多个事务的读操作可以同时进行而不会互相影响&#xff0c;相互不阻塞的。 写锁 : 也称为排他锁 、英文用X表示。当前写操作没有完成前&#xff0c;它会…

《苍穹外卖》项目学习记录-Day11销量排名统计

销量排名需要查两张表&#xff0c;一张是order_detail&#xff0c;它里面有number字段&#xff0c;这个字段体现了商品的销售的份数。我们仅仅查这一张表是不够的&#xff0c;因为用户下单了&#xff0c;下单了之后就会产生订单数据和对应的订单详情数据&#xff0c;假设他下完…

走向基于大语言模型的新一代推荐系统:综述与展望

HightLight 论文题目&#xff1a;Towards Next-Generation LLM-based Recommender Systems: A Survey and Beyond作者机构&#xff1a;吉林大学、香港理工大学、悉尼科技大学、Meta AI论文地址&#xff1a; https://arxiv.org/abs/2410.1974 基于大语言模型的下一代推荐系统&…

Vue3学习笔记-模板语法和属性绑定-2

一、文本插值 使用{ {val}}放入变量&#xff0c;在JS代码中可以设置变量的值 <template><p>{{msg}}</p> </template> <script> export default {data(){return {msg: 文本插值}} } </script> 文本值可以是字符串&#xff0c;可以是布尔…

python算法和数据结构刷题[5]:动态规划

动态规划&#xff08;Dynamic Programming, DP&#xff09;是一种算法思想&#xff0c;用于解决具有最优子结构的问题。它通过将大问题分解为小问题&#xff0c;并找到这些小问题的最优解&#xff0c;从而得到整个问题的最优解。动态规划与分治法相似&#xff0c;但区别在于动态…

【阅读笔记】New Edge Diected Interpolation,NEDI算法,待续

一、概述 由Li等提出的新的边缘指导插值(New Edge—Di-ected Interpolation&#xff0c;NEDI)算法是一种具有良好边缘保持效果的新算法&#xff0c;它利用低分辨率图像与高分辨率图像的局部协方差问的几何对偶性来对高分辨率图像进行自适应插值。 2001年Xin Li和M.T. Orchard…