亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

Asp.net Core 3.1基于AspectCore實(shí)現(xiàn)AOP實(shí)現(xiàn)事務(wù)、緩存攔截器功能

 更新時(shí)間:2020年12月04日 11:32:23   作者:菜工  
這篇文章主要介紹了Asp.net Core 3.1基于AspectCore實(shí)現(xiàn)AOP實(shí)現(xiàn)事務(wù)、緩存攔截器功能,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下

最近想給我的框架加一種功能,就是比如給一個(gè)方法加一個(gè)事務(wù)的特性Attribute,那這個(gè)方法就會(huì)啟用事務(wù)處理。給一個(gè)方法加一個(gè)緩存特性,那這個(gè)方法就會(huì)進(jìn)行緩存。

這個(gè)也是網(wǎng)上說(shuō)的面向切面編程AOP。

AOP的概念也很好理解,跟中間件差不多,說(shuō)白了,就是我可以任意地在方法的前面或后面添加代碼,這很適合用于緩存、日志等處理。

在net core2.2時(shí),我當(dāng)時(shí)就嘗試過(guò)用autofac實(shí)現(xiàn)aop,但這次我不想用autofac,我用了一個(gè)更輕量級(jí)的框架,AspectCore。

用起來(lái)非常非常的簡(jiǎn)單,但一開(kāi)始還是走了一點(diǎn)彎路,主要是網(wǎng)上都是net core3以下的教程,3以下的使用方法跟之前有一些不同。

先安裝NuGet包,包名:AspectCore.Extensions.DependencyInjection

然后在Program.cs類(lèi)中增加一行代碼,這是net core 3的不同之處,這句添加的代碼,意思就是用AspectCore的IOC容器替換內(nèi)置的。因?yàn)锳OP需要依靠IOC實(shí)現(xiàn),所以必須得替換掉內(nèi)置的IOC。

public class Program
  {
    public static void Main(string[] args)
    {
      CreateHostBuilder(args).Build().Run();
    }

    public static IHostBuilder CreateHostBuilder(string[] args) =>
      Host.CreateDefaultBuilder(args)
      .ConfigureWebHostDefaults(webBuilder =>
      {
        webBuilder.UseStartup<Startup>();
      })
      //用AspectCore替換默認(rèn)的IOC容器
      .UseServiceProviderFactory(new DynamicProxyServiceProviderFactory());
}

然后在Startup.cs類(lèi)中的ConfigureServices中添加代碼。(其實(shí)這個(gè)加不加都可以,如果需要配置就加,例如全局的攔截器、只攔截哪些匹配的服務(wù),因?yàn)槲抑挥锰匦赃M(jìn)行攔截,所以我就什么也沒(méi)配置)

services.ConfigureDynamicProxy(o=> { 
   //添加AOP的配置
});

這樣AOP就配置好了,是不是很簡(jiǎn)單。

當(dāng)然使用方面也需要注意一下,可以在接口、接口的方法、類(lèi),類(lèi)的virtual方法上進(jìn)行攔截。還有如果你想攔截控制器的action的話,那需要在ConfigureService里AddControllerAsServices

services.AddControllers()
//把控制器當(dāng)成服務(wù)
.AddControllersAsServices()

下面我列出我的事務(wù)攔截器代碼,如果是特性攔截,就繼承AbstractInterceptorAttribute,如果要寫(xiě)一個(gè)全局?jǐn)r截器,就AbstractInterceptor,然后在ConfigureDynamicProxy中進(jìn)行配置,這個(gè)我就不介紹了

如果你的攔截器是放在其他項(xiàng)目的,那要記得添加AspectCore.Core包,不要只添加AspectCore.Abstractions,我一開(kāi)始就只添加了AspectCore.Abstractions,一直沒(méi)發(fā)現(xiàn)IsAsync、UnwrapAsyncReturnValue等一些擴(kuò)展方法。

public class TransactionInterceptorAttribute : AbstractInterceptorAttribute
  {
    public async override Task Invoke(AspectContext context, AspectDelegate next)
    {
      var dbContext = context.ServiceProvider.GetService<AppDbContext>();
      //先判斷是否已經(jīng)啟用了事務(wù)
      if (dbContext.Database.CurrentTransaction == null)
      {
        await dbContext.Database.BeginTransactionAsync();
        try
        {
          await next(context);
          dbContext.Database.CommitTransaction();
        }
        catch (Exception ex)
        {
          dbContext.Database.RollbackTransaction();
          throw ex;
        }
      }
      else
      {
        await next(context);
      }
    }
  }

然后我就可以這么優(yōu)雅地使用事務(wù)了

我再列出我的緩存攔截器,(感謝網(wǎng)友的提醒,我做了一下修改,針對(duì)異步方法返回值的處理),對(duì)了,下面的ICacheHelper是我定義的一個(gè)緩存助手接口,用的是redis,我會(huì)在后面寫(xiě)一篇博客

public class CacheInterceptorAttribute : AbstractInterceptorAttribute
  {
    /// <summary>
    /// 緩存秒數(shù)
    /// </summary>
    public int ExpireSeconds { get; set; }

    public async override Task Invoke(AspectContext context, AspectDelegate next)
    {
      //判斷是否是異步方法
      bool isAsync = context.IsAsync();
      //if (context.ImplementationMethod.GetCustomAttribute(typeof(AsyncStateMachineAttribute)) != null)
      //{
      //  isAsync = true;
      //}
      //先判斷方法是否有返回值,無(wú)就不進(jìn)行緩存判斷
      var methodReturnType = context.GetReturnParameter().Type;
      if (methodReturnType == typeof(void) || methodReturnType == typeof(Task) || methodReturnType == typeof(ValueTask))
      {
        await next(context);
        return;
      }
      var returnType = methodReturnType;
      if (isAsync)
      {
        //取得異步返回的類(lèi)型
        returnType = returnType.GenericTypeArguments.FirstOrDefault();
      }
      //獲取方法參數(shù)名
      string param = CommonHelper.ObjectToJsonString(context.Parameters);
      //獲取方法名稱,也就是緩存key值
      string key = "Methods:" + context.ImplementationMethod.DeclaringType.FullName + "." + context.ImplementationMethod.Name;
      var cache = context.ServiceProvider.GetService<ICacheHelper>();
      //如果緩存有值,那就直接返回緩存值
      if (cache.HashExists(key, param))
      {
        //反射獲取緩存值,相當(dāng)于cache.HashGet<>(key,param)
        var value = typeof(ICacheHelper).GetMethod(nameof(ICacheHelper.HashGet)).MakeGenericMethod(returnType).Invoke(cache, new[] { key, param });
        if (isAsync)
        {
          //判斷是Task還是ValueTask
          if (methodReturnType == typeof(Task<>).MakeGenericType(returnType))
          {
            //反射獲取Task<>類(lèi)型的返回值,相當(dāng)于Task.FromResult(value)
            context.ReturnValue = typeof(Task).GetMethod(nameof(Task.FromResult)).MakeGenericMethod(returnType).Invoke(null, new[] { value });
          }
          else if (methodReturnType == typeof(ValueTask<>).MakeGenericType(returnType))
          {
            //反射構(gòu)建ValueTask<>類(lèi)型的返回值,相當(dāng)于new ValueTask(value)
            context.ReturnValue = Activator.CreateInstance(typeof(ValueTask<>).MakeGenericType(returnType), value);
          }
        }
        else
        {
          context.ReturnValue = value;
        }
        return;
      }
      await next(context);
      object returnValue;
      if (isAsync)
      {
        returnValue = await context.UnwrapAsyncReturnValue();
        //反射獲取異步結(jié)果的值,相當(dāng)于(context.ReturnValue as Task<>).Result
        //returnValue = typeof(Task<>).MakeGenericType(returnType).GetProperty(nameof(Task<object>.Result)).GetValue(context.ReturnValue);

      }
      else
      {
        returnValue = context.ReturnValue;
      }
      cache.HashSet(key, param, returnValue);
      if (ExpireSeconds > 0)
      {
        cache.SetExpire(key, TimeSpan.FromSeconds(ExpireSeconds));
      }

    }
  }

我還弄了一個(gè)緩存刪除攔截器,作用就是帶有這個(gè)特性的方法執(zhí)行后,會(huì)刪除相關(guān)緩存值

為什么有這個(gè)設(shè)計(jì)呢,比如說(shuō)我給一個(gè)方法 GetUserList 加了緩存,那我數(shù)據(jù)改變了怎么辦,我想在User數(shù)據(jù)改變時(shí),把這個(gè)緩存刪除掉,那我就可以在SaveUser方法上加上我這個(gè)緩存刪除攔截器,那這個(gè)方法執(zhí)行后,就會(huì)把相關(guān)的緩存刪除掉了

public class CacheDeleteInterceptorAttribute : AbstractInterceptorAttribute
{
  private readonly Type[] _types;
  private readonly string[] _methods;

  /// <summary>
  /// 需傳入相同數(shù)量的Types跟Methods,同樣位置的Type跟Method會(huì)組合成一個(gè)緩存key,進(jìn)行刪除
  /// </summary>
  /// <param name="Types">傳入要?jiǎng)h除緩存的類(lèi)</param>
  /// <param name="Methods">傳入要?jiǎng)h除緩存的方法名稱,必須與Types數(shù)組對(duì)應(yīng)</param>
  public CacheDeleteInterceptorAttribute(Type[] Types, string[] Methods)
  {
    if (Types.Length != Methods.Length)
    {
      throw new ApiFailException(ApiFailCode.OPERATION_FAIL, "Types必須跟Methods數(shù)量一致");
    }
    _types = Types;
    _methods = Methods;
  }

  public async override Task Invoke(AspectContext context, AspectDelegate next)
  {
    var cache = context.ServiceProvider.GetService<ICacheHelper>();
    await next(context);
    for (int i = 0; i < _types.Length; i++)
    {
      var type = _types[i];
      var method = _methods[i];
      string key = "Methods:" + type.FullName + "." + method;
      cache.Delete(key);
    }
  }
}

AOP的實(shí)現(xiàn)原理我也想象了一下:

要實(shí)現(xiàn)AOP,需要依靠IOC容器,因?yàn)樗俏覀冾?lèi)的管家,那能被攔截的類(lèi)必須是IOC注入的,自己new出來(lái)的是不受攔截的。如果我想在A方法前面添加點(diǎn)代碼,那我告訴IOC,把代碼給它,那IOC在注入A方法所在類(lèi)時(shí),會(huì)繼承它生成一個(gè)派生類(lèi),然后重寫(xiě)A方法,所以攔截方法必須得為virtual,然后A方法里寫(xiě)上我要添加的代碼,再base.A()這樣。

到此這篇關(guān)于Asp.net Core 3.1基于AspectCore實(shí)現(xiàn)AOP實(shí)現(xiàn)事務(wù)、緩存攔截器功能的文章就介紹到這了,更多相關(guān)Asp.net Core 3.1實(shí)現(xiàn)事務(wù)、緩存攔截器內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • ASP.NET Core處理管道的深入理解

    ASP.NET Core處理管道的深入理解

    這篇文章主要給大家介紹了關(guān)于ASP.NET Core處理管道的深入理解,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2020-11-11
  • ASP.NET?MVC5網(wǎng)站開(kāi)發(fā)項(xiàng)目框架(二)

    ASP.NET?MVC5網(wǎng)站開(kāi)發(fā)項(xiàng)目框架(二)

    這篇文章主要介紹了ASP.NET?MVC5網(wǎng)站開(kāi)發(fā)項(xiàng)目框架,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2015-09-09
  • asp.net Google的translate工具翻譯 API

    asp.net Google的translate工具翻譯 API

    很久前的一天,我想使用這個(gè)東西,然后看了下,GooGle的Translate工具目前沒(méi)有公開(kāi)API,還是一個(gè)逐漸完善的過(guò)程,另一方面,利用一段很小的程序就可以得到我們想要的效果。
    2008-12-12
  • .NET實(shí)現(xiàn)在網(wǎng)頁(yè)中預(yù)覽Office文件的3個(gè)方法

    .NET實(shí)現(xiàn)在網(wǎng)頁(yè)中預(yù)覽Office文件的3個(gè)方法

    這篇文章主要介紹了.NET實(shí)現(xiàn)在網(wǎng)頁(yè)中預(yù)覽Office文件的3個(gè)方法,本文最終采用了ASPOSE+pdf2swf+FlexPaper的方式解決了這個(gè)需求,需要的朋友可以參考下
    2014-10-10
  • 利用Asp.Net Core的MiddleWare思想如何處理復(fù)雜業(yè)務(wù)流程詳解

    利用Asp.Net Core的MiddleWare思想如何處理復(fù)雜業(yè)務(wù)流程詳解

    這篇文章主要給大家介紹了關(guān)于利用Asp.Net Core的MiddleWare思想如何處理復(fù)雜業(yè)務(wù)流程的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起看看吧
    2018-08-08
  • asp.net實(shí)現(xiàn)負(fù)載均衡

    asp.net實(shí)現(xiàn)負(fù)載均衡

    本文給大家分享的是asp.net實(shí)現(xiàn)負(fù)載均衡的方案,是個(gè)人的一些經(jīng)驗(yàn)總結(jié),有需要的小伙伴可以參考下
    2016-01-01
  • ABP(現(xiàn)代ASP.NET樣板開(kāi)發(fā)框架)系列之二、ABP入門(mén)教程詳解

    ABP(現(xiàn)代ASP.NET樣板開(kāi)發(fā)框架)系列之二、ABP入門(mén)教程詳解

    ABP是為新的現(xiàn)代Web應(yīng)用程序使用最佳實(shí)踐和使用最流行工具的一個(gè)起點(diǎn)??勺鳛橐话阌猛镜膽?yīng)用程序的基礎(chǔ)框架或項(xiàng)目模板。接下來(lái)通過(guò)本文給大家詳細(xì)介紹ABP入門(mén)教程,感興趣的朋友一起看看吧
    2017-10-10
  • ASP.NET技巧:請(qǐng)求網(wǎng)址并解析返回的html

    ASP.NET技巧:請(qǐng)求網(wǎng)址并解析返回的html

    ASP.NET技巧:請(qǐng)求網(wǎng)址并解析返回的html...
    2006-09-09
  • CHECKBOX 的全選、取消及跨頁(yè)保存的實(shí)現(xiàn)方法

    CHECKBOX 的全選、取消及跨頁(yè)保存的實(shí)現(xiàn)方法

    CHECKBOX的操作在頁(yè)面中很常見(jiàn),比如全選、取消、跨頁(yè)保存等等,下面有個(gè)不錯(cuò)的示例,大家可以嘗試操作下
    2013-10-10
  • ASP.NET操作EXCEL的總結(jié)篇

    ASP.NET操作EXCEL的總結(jié)篇

    今年有個(gè)系統(tǒng)的部分EXCEL的操作也讓我做,順便結(jié)合之前操作EXCEL的經(jīng)驗(yàn)作一下總結(jié),可能也算不上什么,對(duì)于絕大多數(shù)來(lái)說(shuō)也沒(méi)什么技術(shù)含量,網(wǎng)上一搜一大把,但我想還是有必要總結(jié)一下
    2011-02-02

最新評(píng)論