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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM