目录
二、首先先nuget安装UtilsSharp.AsyncInterceptor
一、前言
我们都知道Castle动态代理是对于同步方法的动态代理,那么我们介绍下如何使用Castle来对异步方法进行代理。
如果你站在应用程序的角度来看,异步只是微软的一个语法糖,使用异步的方法返回结果为一个Task/ValueTask或Task/ValueTask的对象,这对于DP来说和一个int类型并无差别,但是如果我们想要在拦截中获取到真实的返回结果,就需要添加一些额外的处理。
查了些资料,都是推荐我们使用这个异步拦截框架Castle.Core.AsyncInterceptor,但是这个库有个缺点就是仅支持Task,Task<TResult>,却不支持ValueTask,ValueTask<TResult> 。后面基于Castle.Core.AsyncInterceptor封装了支持ValueTask,ValueTask<TResult>的异步拦截框架:UtilsSharp.AsyncInterceptor
二、首先先nuget安装UtilsSharp.AsyncInterceptor

三、异步拦截类
异步拦截类主要是处理同步方法和异步方法的拦截,可以支持拦截 void、TResult、Task、Task<TResult>、ValueTask、ValueTask<TResult>的方法
/// <summary>
/// 日志异步拦截
/// </summary>
public class LoggerAsyncInterceptor : IAsyncInterceptor
{
/// <summary>
/// Exception 匹配规则
/// </summary>
public virtual List<ExceptionRegexRule> ExceptionRegexRule { set; get; } = BaseException.GetDefaultRegexRule();
#region 同步方法拦截时使用
/// <summary>
/// 同步方法拦截时使用
/// </summary>
/// <param name="invocation"></param>
public virtual void InterceptSynchronous(IInvocation invocation)
{
try
{
invocation.Proceed();
}
catch (Exception ex)
{
InterceptorException.Interceptor(invocation, ex, ExceptionRegexRule);
}
}
#endregion
#region 异步方法返回Task拦截时使用
/// <summary>
/// 异步方法返回Task拦截时使用
/// </summary>
/// <param name="invocation">IInvocation</param>
public virtual void InterceptTaskAsynchronous(IInvocation invocation)
{
//调用业务方法
invocation.ReturnValue = InternalInterceptTaskAsynchronous(invocation);
}
/// <summary>
/// 异步方法返回Task`1拦截时使用 私有方法
/// </summary>
/// <param name="invocation">IInvocation</param>
/// <returns></returns>
protected virtual async Task InternalInterceptTaskAsynchronous(IInvocation invocation)
{
try
{
//获取执行信息
invocation.Proceed();
var task = (Task)invocation.ReturnValue;
await task;
//记录日志
}
catch (Exception ex)
{
InterceptorException.Interceptor(invocation, ex, ExceptionRegexRule);
}
}
#endregion
#region 异步方法返回Task<TResult>拦截时使用
/// <summary>
/// 异步方法返回Task`1拦截时使用
/// </summary>
/// <typeparam name="TResult">返回参数</typeparam>
/// <param name="invocation">IInvocation</param>
public virtual void InterceptTaskAsynchronous<TResult>(IInvocation invocation)
{
//调用业务方法
invocation.ReturnValue = InternalInterceptTaskAsynchronous<TResult>(invocation);
}
/// <summary>
/// 异步方法返回Task`1拦截时使用 私有方法
/// </summary>
/// <typeparam name="TResult">返回参数</typeparam>
/// <param name="invocation">IInvocation</param>
/// <returns></returns>
protected virtual async Task<TResult> InternalInterceptTaskAsynchronous<TResult>(IInvocation invocation)
{
try
{
//获取执行信息
invocation.Proceed();
var task = (Task<TResult>)invocation.ReturnValue;
TResult result = await task;
//记录日志
return result;
}
catch (Exception ex)
{
return InterceptorException.InterceptorAsync<TResult>(invocation, ex, ExceptionRegexRule);
}
}
#endregion
#region 异步方法返回ValueTask拦截时使用
/// <summary>
/// 异步方法返回ValueTask拦截时使用
/// </summary>
/// <param name="invocation">IInvocation</param>
public virtual void InterceptValueTaskAsynchronous(IInvocation invocation)
{
//调用业务方法
invocation.ReturnValue = InternalInterceptValueTaskAsynchronous(invocation);
}
/// <summary>
/// 异步方法返回ValueTask拦截时使用 私有方法
/// </summary>
/// <param name="invocation">IInvocation</param>
/// <returns></returns>
protected virtual async ValueTask InternalInterceptValueTaskAsynchronous(IInvocation invocation)
{
try
{
//获取执行信息
invocation.Proceed();
var task = (ValueTask)invocation.ReturnValue;
await task;
//记录日志
}
catch (Exception ex)
{
InterceptorException.Interceptor(invocation, ex, ExceptionRegexRule);
}
}
#endregion
#region 异步方法返回ValueTask<TResult>拦截时使用
/// <summary>
/// 异步方法返回ValueTask`1拦截时使用
/// </summary>
/// <typeparam name="TResult">返回参数</typeparam>
/// <param name="invocation">IInvocation</param>
public virtual void InterceptValueTaskAsynchronous<TResult>(IInvocation invocation)
{
//调用业务方法
invocation.ReturnValue = InternalInterceptValueTaskAsynchronous<TResult>(invocation);
}
/// <summary>
/// 异步方法返回ValueTask`1拦截时使用 私有方法
/// </summary>
/// <typeparam name="TResult">返回参数</typeparam>
/// <param name="invocation">IInvocation</param>
/// <returns></returns>
protected virtual async ValueTask<TResult> InternalInterceptValueTaskAsynchronous<TResult>(IInvocation invocation)
{
try
{
//获取执行信息
invocation.Proceed();
var task = (ValueTask<TResult>)invocation.ReturnValue;
TResult result = await task;
//记录日志
return result;
}
catch (Exception ex)
{
return InterceptorException.InterceptorAsync<TResult>(invocation, ex, ExceptionRegexRule);
}
}
#endregion
}
四、拦截器
然后,定义拦截器,实现IInterceptor接口
/// <summary>
/// 异步拦截
/// </summary>
/// <typeparam name="TAsyncInterceptor">异步拦截服务</typeparam>
public class AsyncInterceptor<TAsyncInterceptor> : IInterceptor where TAsyncInterceptor : IAsyncInterceptor
{
private readonly TAsyncInterceptor _t;
/// <summary>
/// 异步拦截
/// </summary>
public AsyncInterceptor(TAsyncInterceptor t)
{
_t = t;
}
/// <summary>
/// 拦截主方法
/// </summary>
/// <param name="invocation"></param>
public void Intercept(IInvocation invocation)
{
_t.ToInterceptor().Intercept(invocation);
}
}
五、异常拦截信息处理
这个类主要是实现对try{}catch{}异常捕捉后的消息进行日志记录和返回参赋值。返回参如果是BaseResult<T>、Task<BaseResult<T>>、ValueTask<BaseResult<T>>类型的,会把错误信息自动赋值上去。本类依赖UtilSharp 3.4.0和UtilSharp.Logger 2.0.0
/// <summary>
/// 拦截异常信息
/// </summary>
public class InterceptorException
{
#region 拦截异常信息
/// <summary>
/// 拦截异常信息
/// </summary>
/// <param name="invocation">IInvocation</param>
/// <param name="ex">Exception</param>
/// <param name="rules">Exception 拦截规则</param>
public static void Interceptor(IInvocation invocation, Exception ex, List<ExceptionRegexRule> rules)
{
var result = Result(invocation, ex, rules);
invocation.ReturnValue = result;
}
/// <summary>
/// 拦截异常信息(异步带参数)
/// </summary>
/// <typeparam name="TResult">TResult</typeparam>
/// <param name="invocation">IInvocation</param>
/// <param name="ex">Exception</param>
/// <param name="rules">Exception 拦截规则</param>
/// <returns></returns>
public static TResult InterceptorAsync<TResult>(IInvocation invocation, Exception ex, List<ExceptionRegexRule> rules)
{
var result = Result(invocation, ex, rules);
return (TResult)result;
}
/// <summary>
/// 获取错误信息
/// </summary>
/// <param name="invocation">IInvocation</param>
/// <param name="ex">Exception</param>
/// <param name="rules">Exception 拦截规则</param>
/// <returns></returns>
private static object Result(IInvocation invocation, Exception ex, List<ExceptionRegexRule> rules)
{
// 判断方法是否为异步方法
MethodInfo methodInfo = invocation.Method;
bool isAsyncMethod = IsAsyncMethod(methodInfo);
//同步方法
var returnType = invocation.Method.ReturnType;
if (isAsyncMethod)
{ //异步方法
returnType = invocation.Method.ReturnType.GetGenericArguments().First();
}
var setErrorMethod = returnType.GetMethod("SetError", new Type[] { typeof(string), typeof(int) });
var result = returnType != typeof(string) ? Activator.CreateInstance(returnType, true) : "";
var methodName = invocation.InvocationTarget + "." + invocation.Method.Name;
var args = new List<string>();
if (invocation.Arguments != null && invocation.Arguments.Length > 0)
{
args.AddRange(from item in invocation.Arguments where item != null select JsonConvert.SerializeObject(item));
}
var param = string.Join(",", args);
if (setErrorMethod == null)
{
LogHelper.Error($"执行:{methodName} 异常", ex, parameters: $"{param}", func: $"{methodName}");
}
else
{
var logId = LogHelper.Error($"{methodName} 异常", ex, parameters: $"{param}", func: $"{methodName}");
var r = ex.Regex(logId, rules);
setErrorMethod.Invoke(result, new object[] { r.Msg, r.Code });
}
return result;
}
/// <summary>
/// 判断是否是异步方法
/// </summary>
/// <param name="methodInfo">方法信息</param>
/// <returns></returns>
private static bool IsAsyncMethod(MethodInfo methodInfo)
{
return typeof(System.Threading.Tasks.Task).IsAssignableFrom(methodInfo.ReturnType) ||
(methodInfo.ReturnType.IsGenericType &&
methodInfo.ReturnType.GetGenericTypeDefinition() == typeof(System.Threading.Tasks.Task<>));
}
#endregion
}
六、Autofac的集成
Autofac集成了对DynamicProxy的支持,我们需要引用Autofac.Extras.DynamicProxy,然后创建容器、注册服务、生成实例、调用方法,我们来看下面的代码:
static void Main(string[] args)
{
ContainerBuilder builder = new ContainerBuilder();
//注册拦截器
builder.RegisterType<AsyncInterceptor<LoggerAsyncInterceptor>>().AsSelf();
builder.RegisterType<LoggerAsyncInterceptor>().AsSelf();
//注册要拦截的服务
builder.RegisterType<ProductRepository>().AsImplementedInterfaces()
.EnableInterfaceInterceptors() //启用接口拦截
.InterceptedBy(typeof(AsyncInterceptor<LoggerAsyncInterceptor>)); //指定拦截器
var container = builder.Build();
IProductRepository productRepo = container.Resolve<IProductRepository>();
productRepo.Get();
}
七、.Net Core 3.1上使用
前面是跟大家展示详细的实现过程,如果大家是.Net Core 3.1 项目,不用去写上面那些代码,可以nuget直接安装UtilsSharp.AspNetCore框架(2.1.1以上版本),UtilsSharp.AspNetCore 3.4.0已经集成了UtilsSharp.AsyncInterceptor和Autofac.Extras.DynamicProxy框架,只要在Startup.cs文件这么简单配置即可
public class Startup : AutofacStartup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
//初始化Protobuf模型
//ProtobufRunTime.Initialize();
// 验证入参模型
//services.AddValidationExtensions();
//ElasticSearch配置
//ElasticSearchConfig.ElasticSearchSetting = JsonConvert.DeserializeObject<ElasticSearchSetting>(BaseConfig.EsSettingJson);
//MQ队列配置
//RabbitMqConfig.RabbitMqSetting = new RabbitMqSetting { RabbitMqConnection =BaseConfig.RabbitMqConnection};
//RabbitMqManager.Register();
//swagger配置
AspNetCoreExtensionsConfig.SwaggerDocOptions = new SwaggerDocOptions
{
Enable = true,
ProjectName = "日志管理中心",
ProjectDescription = "日志管理中心接口",
Groups = new List<SwaggerGroup>
{
new SwaggerGroup() {GroupName = "log", Title = "日志记录接口", Version = "v1.0"}
}
};
//ThreadPool.SetMinThreads(500, 400);
services.AddAspNetCoreExtensions();
services.AddControllers().AddNewtonsoftJson();
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
//注册扩展
app.UseAspNetCoreExtensions();
app.UseRouting();
app.UseEndpoints(endpoints =>
{
//配置控制器映射
endpoints.MapControllers();
});
}
/// <summary>
/// 依赖注入映射
/// </summary>
/// <param name="builder"></param>
public override void ConfigureContainer(ContainerBuilder builder)
{
Init<AsyncInterceptor<LoggerAsyncInterceptor>>(builder);
}
}
主要关键代码是最后这个配置下,大家还可以按自己的拦截需求重写LoggerAsyncInterceptor这个类
/// <summary>
/// 依赖注入映射
/// </summary>
/// <param name="builder"></param>
public override void ConfigureContainer(ContainerBuilder builder)
{
Init<AsyncInterceptor<LoggerAsyncInterceptor>>(builder);
}
本文介绍了如何使用Castle.Core AsyncInterceptor 对.NET Core 3.1的异步方法进行拦截,并结合Autofac和UtilsSharp AsyncInterceptor,实现异常处理和日志记录,同时演示了如何集成Autofac以方便服务注册和依赖注入。


1664

被折叠的 条评论
为什么被折叠?



