AspectCore是適用於Asp.Net Core 平臺的輕量級Aop(Aspect oriented programming)解決方案,它更好的遵循Asp.Net Core的模塊化開發理念,使用AspectCore可以更容易構建低耦合、易擴展的Web應用程式。 在使用過程中,由於相關文檔、博客還 ...
AspectCore是適用於Asp.Net Core 平臺的輕量級Aop(Aspect-oriented programming)解決方案,它更好的遵循Asp.Net Core的模塊化開發理念,使用AspectCore可以更容易構建低耦合、易擴展的Web應用程式。
在使用過程中,由於相關文檔、博客還未更新到.Net Core 3.0,本文操作參考了使用.Net Core 3.0的EasyCaching,並對其中公用的方法進行封裝簡化。
安裝Aspectcore
此處配合微軟自家的DI實現,安裝Nuget包AspectCore.Extensions.DependencyInjection,其中包含AspectCore.Core和Microsoft.Extensions.DependencyInjection兩個依賴。
Install-Package AspectCore.Extensions.DependencyInjection -Version 1.3.0
攔截器
- 特性攔截器
新建一個特性攔截器TestInterceptorAttribute,繼承AbstractInterceptorAttribute,並重寫Invoke方法,在方法中實現攔截相關業務。
public class TestInterceptorAttribute : AbstractInterceptorAttribute
{
public override Task Invoke(AspectContext context, AspectDelegate next)
{
return context.Invoke(next);
}
}
- 全局攔截器
新建一個全局攔截器TestInterceptor,繼承AbstractInterceptor,並重寫Invoke方法,在方法中實現攔截相關業務。
public class TestInterceptor : AbstractInterceptor
{
public override Task Invoke(AspectContext context, AspectDelegate next)
{
return context.Invoke(next);
}
}
註冊服務
以下註冊方式僅適用於asp.net core 3.0(目前只到3.0),已知在2.2版本中,需要在ConfigureServices方法中返回IServiceProvider,並且program.cs中也不再需要替換ServiceProviderFactory。
1.創建AspectCoreEctensions.cs擴展IServiceCollection
public static class AspectCoreExtensions
{
public static void ConfigAspectCore(this IServiceCollection services)
{
services.ConfigureDynamicProxy(config =>
{
//TestInterceptor攔截器類
//攔截代理所有Service結尾的類
config.Interceptors.AddTyped<TestInterceptor>(Predicates.ForService("*Service"));
});
services.BuildAspectInjectorProvider();
}
}
2.在Startup.cs中註冊服務
public void ConfigureServices(IServiceCollection services)
{
services.ConfigAspectCore();
}
3.在Program.cs中替換ServiceProviderFactory
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
}).UseServiceProviderFactory(new AspectCoreServiceProviderFactory());
被攔截方法編寫
- 代理介面:在介面上標註Attribute
public interface ITestService
{
[TestInterceptor]
void Test();
}
- 代理類(方法):在方法上標註Attribute,並且標註virtual
public class TestService
{
[TestInterceptor]
public virtual void Test()
{
//業務代碼
}
}
攔截器業務編寫
- 執行被攔截方法
private async Task<object> RunAndGetReturn()
{
await Context.Invoke(Next);
return Context.IsAsync()
? await Context.UnwrapAsyncReturnValue()
: Context.ReturnValue;
}
- 攔截器中的依賴註入
[FromContainer]
private RedisClient RedisClient { get; set; }
- 獲取被攔截方法的Attribute
private static readonly ConcurrentDictionary<MethodInfo, object[]>
MethodAttributes = new ConcurrentDictionary<MethodInfo, object[]>();
public static T GetAttribute<T>(this AspectContext context) where T : Attribute
{
MethodInfo method = context.ServiceMethod;
var attributes = MethodAttributes.GetOrAdd(method, method.GetCustomAttributes(true));
var attribute = attributes.FirstOrDefault(x => typeof(T).IsAssignableFrom(x.GetType()));
if (attribute is T)
{
return (T)attribute;
}
return null;
}
- 獲取被攔截方法返回值類型
public static Type GetReturnType(this AspectContext context)
{
return context.IsAsync()
? context.ServiceMethod.ReturnType.GetGenericArguments()First()
: context.ServiceMethod.ReturnType;
}
- 處理攔截器返回結果
private static readonly ConcurrentDictionary<Type, MethodInfo>
TypeofTaskResultMethod = new ConcurrentDictionary<Type, MethodInfo>();
public object ResultFactory(this AspectContext context,object result)
{
var returnType = context.GetReturnType();
//非同步方法返回Task<T>類型結果
if (context.IsAsync())
{
return TypeofTaskResultMethod
.GetOrAdd(returnType, t => typeof(Task)
.GetMethods()
.First(p => p.Name == "FromResult" && p.ContainsGenericParameters)
.MakeGenericMethod(returnType))
.Invoke(null, new object[] { result });
}
else
{
return result;
}
}