Asp Net Core Filter(过滤器)

## 1.Asp Net Core Filter(过滤器)

1.1 Filter简介

(1)面向切面编程

(2)ASP.NET Core中的Filter的五种类型:Authorization filter、Resource filter、Action filter、Exception filter、Result filter。所有筛选器一般有同步和异步两个版本,比如IActionFilter、IAsyncActionFilter接口。

1.2 Exception Filter

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

(1)继承IAsyncExceptionFilter

public class MyExceptionFilter : IAsyncExceptionFilter
{
    private readonly ILogger<MyExceptionFilter> logger;
    private readonly IHostEnvironment env;
    public MyExceptionFilter(ILogger<MyExceptionFilter> logger, IHostEnvironment env)
    {
        this.logger = logger;
        this.env = env;
    }
    public Task OnExceptionAsync(ExceptionContext context)
    {
        Exception exception = context.Exception;
        logger.LogError(exception, "UnhandledException occured");
        string message;
        if (env.IsDevelopment())
        {
            message = exception.ToString();
        }
        else
        {
            message = "程序中出现未处理异常";
        }
        ObjectResult result = new ObjectResult(new { code = 500, message = message });
        result.StatusCode = 500;
        context.Result = result;
        //设置剩下的IAsyncExceptionFilter不执行
        context.ExceptionHandled = true;
        return Task.CompletedTask;
    }
}

(2)IServiceCollection注入

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

1.3 ActionFilter

多个Action Filter的链式执行

image-20220308200057053

(1)继承IAsyncActionFilter

ActionFilter1

using Microsoft.AspNetCore.Mvc.Filters;

public class ActionFilter1 : IAsyncActionFilter
{
    public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
    {
        Console.WriteLine("ActionFilter1:开始执行");
        ActionExecutedContext r = await next();
        if (r.Exception != null)
        {
            Console.WriteLine("MyActionFilter 1:执行失败");
        }
        else
        {
            Console.WriteLine("MyActionFilter 1:执行成功");
        }
    }
}

ActionFilter2


using Microsoft.AspNetCore.Mvc.Filters;

public class ActionFilter2 : IAsyncActionFilter
{
    public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
    {
        Console.WriteLine("ActionFilter2:开始执行");
        ActionExecutedContext r = await next();
        if (r.Exception != null)
        {
            Console.WriteLine("MyActionFilter 2:执行失败");
        }
        else
        {
            Console.WriteLine("MyActionFilter 2:执行成功");
        }
    }
}

(2)IServiceCollection服务注入

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

(3)访问接口,查看ActionFilter执行顺序

image-20220308200757465

1.4 自动启用事务的ActionFilter

(1)TransactionScope

  • TransactionScope实现了IDisposable接口,如果一个TransactionScope的对象没有调用Complete()就执行了Dispose()方法,则事务会被回滚,否则事务就会被提交
  • TransactionScope还支持嵌套式事务
  • .NET Core中的TransactionScope不像.NET FX一样有MSDTC分布式事务提升的问题。请使用最终一致性事务

(2)继承IAsyncActionFilter

这个特性标注在不需要执行事务的方法上

/// <summary>
/// 只允许写在方法上
/// </summary>
[AttributeUsage(AttributeTargets.Method)]
public class NotTransactionalAttribute : Attribute
{
}

TransactionScopeFilter

 public class TransactionScopeFilter : IAsyncActionFilter
    {
        public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
        {
			bool hasNotTransactionalAttribute = false;
			if (context.ActionDescriptor is ControllerActionDescriptor)
			{
				var actionDesc = (ControllerActionDescriptor)context.ActionDescriptor;
				hasNotTransactionalAttribute = actionDesc.MethodInfo
					.IsDefined(typeof(NotTransactionalAttribute));
			}
			if (hasNotTransactionalAttribute)
			{
				await next();
				return;
			}
			using var txScope =
					new TransactionScope(TransactionScopeAsyncFlowOption.Enabled);
			var result = await next();
			if (result.Exception == null)
			{
				txScope.Complete();
			}
		}
    }

(3)IServiceCollection服务注入

builder.Services.AddDbContext<MyDbContext>(opt => {
    string connStr = builder.Configuration.GetConnectionString("Default");
    opt.UseSqlServer(connStr);
});
builder.Services.Configure<MvcOptions>(options =>
{
    options.Filters.Add<TransactionScopeFilter>();
});

1.5请求限流的ActionFilter

实现“一秒钟内只允许最多有一个来自同一个IP地址的请求”

(1)继承IAsyncActionFilter

public class RateLimiterFilter : IAsyncActionFilter
{
    private readonly IMemoryCache memCache;
    public RateLimiterFilter(IMemoryCache memCache)
    {
        this.memCache = memCache;
    }

    public Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
    {
        string removeIP = context.HttpContext.Connection.RemoteIpAddress.ToString();
        string cacheKey = $"LastVisitTick_{removeIP}";
        long? lastTick = memCache.Get<long?>(cacheKey);
        //如果上次访问时间不存在,或者访问间隔一秒内
        if (lastTick == null || Environment.TickCount64 - lastTick > 1000)
        {
            //设置过期时间10s
            memCache.Set(cacheKey, Environment.TickCount64, TimeSpan.FromSeconds(10));
            return next();
        }
        else
        {
            context.Result = new ContentResult { StatusCode = 429, Content = "访问频繁" };
            return Task.CompletedTask;
        }
    }
}

(2)IServiceCollection服务注入

builder.Services.AddMemoryCache();
builder.Services.Configure<MvcOptions>(options =>
{
    options.Filters.Add<RateLimiterFilter>();
});
posted @ 2022-04-08 15:45  peng_boke  阅读(888)  评论(0编辑  收藏  举报