這次學習主要參考了Edison zhou 的這篇文章:https://www.cnblogs.com/edisonchou/p/9159644.html,相關的概念也做了解釋,有興趣的可以了解一下
本次實現需要引用以下包,版本也有要求(包括Autofac),稍后會進行解釋。 我先把實現邏輯講完,再分享其中遇到的坑
如果對AspectCore不太了解的,可以下載查看AspectCoreDemo ,了解AspectCore攔截器設置。
使用AspectCore前,把原來的Castle相關引用刪除,避免沖突,同時前文提到的 LogInterceptor , MyInterceptor 先注釋相關代碼,后續會使用 AspectCore 實現基於方法的攔截
首先新建自定義攔截類CustomInterceptorAttribute ,這里要using AspectCore.DynamicProxy;
/// <summary> /// 自定義攔截器 /// </summary> public class CustomInterceptorAttribute : AbstractInterceptorAttribute { /// <summary> /// 每個被攔截的方法中執行 /// </summary> /// <param name="context"></param> /// <param name="next"></param> /// <returns></returns> public override async Task Invoke(AspectContext context, AspectDelegate next) { try { Console.WriteLine("Before service call"); await next(context); // 執行被攔截的方法 } catch (Exception) { Console.WriteLine("Service threw an exception"); throw; } finally { Console.WriteLine("After service call"); } } }
依賴注入是借助Autofac ,在Program.cs 增加如下代碼 .UseServiceProviderFactory(new AutofacServiceProviderFactory())
public static IHostBuilder CreateHostBuilder(string[] args) => Host.CreateDefaultBuilder(args) .UseServiceProviderFactory(new AutofacServiceProviderFactory()) //autofac 依賴注入 .ConfigureWebHostDefaults(webBuilder => { webBuilder.UseStartup<Startup>(); });
在Startup.cs 的ConfigureContainer 方法最后加入一行代碼 添加引用 AspectCore.Extensions.Autofac
builder.RegisterDynamicProxy();
AspectCore 配置完成了,接下來是 Polly+AspectCore 結合使用
這里引用楊中科老師封裝的 RuPeng.HystrixCore ,里面定義好了相關Polly配置和執行邏輯,后續只要添加相關屬性值就可以實現動態配置。
同步引用 AspectCore.Core, Microsoft.Extensions.Caching.Memory(對熔斷后操作數據做緩存)
接下來是調用方法。
新建IProductService.cs
在相關的接口添加Polly屬性配置,具體的屬性含義可以查看 RuPeng.HystrixCore 源代碼,GetAllProductsFallBackAsync 是Fallback接口
public interface IProductService { [HystrixCommand(nameof(GetAllProductsFallBackAsync), EnableCircuitBreaker = true, CacheTTLMilliseconds =1000*6, ExceptionsAllowedBeforeBreaking = 2, MillisecondsOfBreak = 1000 * 6)] string GetAllProductsAsync(string productType); string GetAllProductsFallBackAsync(string productType); }
ProductService.cs
public class ProductService : IProductService { public string GetAllProductsAsync(string productType) { NLogHelper.logger.Info("test for GetAllProductsAsync:" + productType); string str = null; str.ToString(); // to do : using HttpClient to call outer service to get product list return $"OK {productType}"; } public string GetAllProductsFallBackAsync(string productType) { NLogHelper.logger.Info("test for GetAllProductsFallBackAsync:"+productType); return $"OK for FallBack {productType}"; } }
新建ProductController.cs
[Route("api/[controller]/[action]")] [ApiController] public class ProductController : ControllerBase { private readonly IProductService _baseService; public ProductController(IProductService baseService) { _baseService = baseService; } [HttpGet] public async Task<string> Get(string productType="A") { var product = _baseService.GetAllProductsAsync(productType); return product; } }
注意,Get方法用異步線程
最后調試:
調試完,接着說說版本號的問題以及遇到的坑
最初引用 AspectCore.Extensions.Autofac 注入匿名代理時,無法編譯通過,提示Method not found: 'Autofac.Builder.DeferredCallback Autofac.ContainerBuilder.RegisterCallback(System.Action`1<Autofac.Core.IComponentRegistry>)'.
后來 在AspectCore-Framwork 項目提交issues ,解釋說已處理但沒發布,暫時可以先降級Autofac到4.9 版本,於是把相關的引用降級,編譯通過
在引用 RuPeng.HystrixCore 調試時有個bug,fallback接口沒有把參數傳過來,導致每次傳不同參數調用接口都是返回之前的參數值,后來下載源碼修改
Object fallBackResult = fallBackMethod.Invoke(context.Implementation, context.Parameters);
改為
Object fallBackResult = fallBackMethod.Invoke(context.Implementation, aspectContext.Parameters);
編譯后替換,問題解決
此外RuPeng.HystrixCore 不兼容Polly 7 ,所以要把Polly 版本降為6.0.1