AspectCore是適用于Asp.Net Core 平臺的輕量級Aop(Aspect-oriented programming)解決方案,它更好的遵循Asp.Net Core的模塊化開發(fā)理念,使用AspectCore可以更容易構(gòu)建低耦合、易擴展的Web應用程序。
在使用過程中,由于相關(guān)文檔、博客還未更新到.Net Core 3.0,本文操作參考了使用.Net Core 3.0的EasyCaching,并對其中公用的方法進行封裝簡化。
安裝Aspectcore
此處配合微軟自家的DI實現(xiàn),安裝Nuget包AspectCore.Extensions.DependencyInjection,其中包含AspectCore.Core和Microsoft.Extensions.DependencyInjection兩個依賴。
Install-Package AspectCore.Extensions.DependencyInjection -Version 1.3.0
攔截器
- 特性攔截器
新建一個特性攔截器TestInterceptorAttribute,繼承AbstractInterceptorAttribute,并重寫Invoke方法,在方法中實現(xiàn)攔截相關(guān)業(yè)務(wù)。
public class TestInterceptorAttribute : AbstractInterceptorAttribute
{
public override Task Invoke(AspectContext context, AspectDelegate next)
{
return context.Invoke(next);
}
}
- 全局攔截器
新建一個全局攔截器TestInterceptor,繼承AbstractInterceptor,并重寫Invoke方法,在方法中實現(xiàn)攔截相關(guān)業(yè)務(wù)。
public class TestInterceptor : AbstractInterceptor
{
public override Task Invoke(AspectContext context, AspectDelegate next)
{
return context.Invoke(next);
}
}
注冊服務(wù)
以下注冊方式僅適用于asp.net core 3.0(目前只到3.0),已知在2.2版本中,需要在ConfigureServices方法中返回IServiceProvider,并且program.cs中也不再需要替換ServiceProviderFactory。
1.創(chuàng)建AspectCoreEctensions.cs擴展IServiceCollection
public static class AspectCoreExtensions
{
public static void ConfigAspectCore(this IServiceCollection services)
{
services.ConfigureDynamicProxy(config =>
{
//TestInterceptor攔截器類
//攔截代理所有Service結(jié)尾的類
config.Interceptors.AddTyped<TestInterceptor>(Predicates.ForService("*Service"));
});
services.BuildAspectInjectorProvider();
}
}
2.在Startup.cs中注冊服務(wù)
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());
被攔截方法編寫
public interface ITestService
{
[TestInterceptor]
void Test();
}
- 代理類(方法):在方法上標注Attribute,并且標注virtual
public class TestService
{
[TestInterceptor]
public virtual void Test()
{
//業(yè)務(wù)代碼
}
}
攔截器業(yè)務(wù)編寫
private async Task<object> RunAndGetReturn()
{
await Context.Invoke(Next);
return Context.IsAsync()
? await Context.UnwrapAsyncReturnValue()
: Context.ReturnValue;
}
[FromContainer]
private RedisClient RedisClient { get; set; }
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>類型結(jié)果
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;
}
}
相關(guān)鏈接
|