如何拦截WebJob函数调用?统一封装避免重复代码
拦截WebJobs函数调用的全局化方案
当然有办法实现全局的WebJobs函数调用拦截,完全不用在数百个触发器里重复编写分析代码!结合你熟悉的IJobActivator,我整理了几个实用的方案,覆盖不同场景:
1. 利用WebJobs SDK自带的Filter机制(最推荐)
WebJobs SDK提供了**IFunctionInvocationFilter和IFunctionExceptionFilter**接口,这是官方原生的全局拦截方案,可以轻松实现调用前后的分析、异常捕获逻辑,而且不需要修改任何Job的代码。
实现步骤:
- 自定义一个实现
IFunctionInvocationFilter的过滤器,在OnExecutingAsync和OnExecutedAsync中添加你的调用分析逻辑:
public class FunctionInvocationAnalysisFilter : IFunctionInvocationFilter { public async Task OnExecutingAsync(FunctionExecutingContext context, CancellationToken cancellationToken) { // 调用前的分析逻辑:记录调用时间、函数名、参数等 Console.WriteLine($"开始执行函数: {context.FunctionName},时间: {DateTime.Now}"); } public async Task OnExecutedAsync(FunctionExecutedContext context, CancellationToken cancellationToken) { // 调用后的分析逻辑:记录执行时长、结果状态等 var duration = DateTime.Now - context.FunctionStartTime; Console.WriteLine($"函数 {context.FunctionName} 执行完成,耗时: {duration.TotalMilliseconds}ms"); if (context.Exception != null) { Console.WriteLine($"函数执行异常: {context.Exception.Message}"); } } }
- 在WebJobs的配置中全局注册这个过滤器:
var config = new JobHostConfiguration(); config.Filters.Add(new FunctionInvocationAnalysisFilter()); var host = new JobHost(config); host.RunAndBlock();
这个方案的优势是完全原生、侵入性极低,一次配置就能覆盖所有函数,非常适合你的多项目场景。
2. 基于IJobActivator的装饰器模式
既然你已经熟悉IJobActivator,可以通过它返回被装饰的Job实例,在装饰器中封装调用分析逻辑。
实现步骤:
- 定义一个通用的Job装饰器,包装目标Job的执行逻辑:
public class JobDecorator<TJob> : TJob where TJob : class, IJob { private readonly TJob _innerJob; public JobDecorator(TJob innerJob) { _innerJob = innerJob; } public async Task ExecuteAsync(CancellationToken cancellationToken) { // 执行前分析 Console.WriteLine($"准备执行Job: {typeof(TJob).Name}"); var startTime = DateTime.Now; // 调用原Job的执行方法 await _innerJob.ExecuteAsync(cancellationToken); // 执行后分析 var duration = DateTime.Now - startTime; Console.WriteLine($"Job {typeof(TJob).Name} 执行完成,耗时: {duration.TotalMilliseconds}ms"); } }
- 自定义
IJobActivator,在创建Job实例时返回装饰后的对象:
public class DecoratingJobActivator : IJobActivator { private readonly IServiceProvider _serviceProvider; public DecoratingJobActivator(IServiceProvider serviceProvider) { _serviceProvider = serviceProvider; } public T CreateInstance<T>() { // 从DI获取原生Job实例 var innerJob = _serviceProvider.GetService<T>(); // 返回装饰后的实例 return (T)Activator.CreateInstance(typeof(JobDecorator<>).MakeGenericType(typeof(T)), innerJob); } }
- 注册自定义的Activator到WebJobs配置:
var config = new JobHostConfiguration(); config.JobActivator = new DecoratingJobActivator(serviceProvider); var host = new JobHost(config); host.RunAndBlock();
这个方案适合你已经在使用自定义IJobActivator的场景,通过装饰器模式扩展原有逻辑。
3. 结合依赖注入的拦截器(如Autofac)
如果你的项目使用了Autofac作为DI容器,可以利用Autofac的拦截器功能,全局拦截所有Job的方法调用。
实现步骤:
- 定义一个Autofac拦截器:
public class JobInvocationInterceptor : IInterceptor { public void Intercept(IInvocation invocation) { // 执行前逻辑 Console.WriteLine($"拦截到Job方法调用: {invocation.Method.Name}"); var startTime = DateTime.Now; // 执行原方法 invocation.Proceed(); // 执行后逻辑 var duration = DateTime.Now - startTime; Console.WriteLine($"方法 {invocation.Method.Name} 执行完成,耗时: {duration.TotalMilliseconds}ms"); } }
- 在Autofac容器中注册Job类型,并启用拦截:
var builder = new ContainerBuilder(); // 注册所有Job类型 builder.RegisterAssemblyTypes(typeof(MyJob).Assembly) .Where(t => typeof(IJob).IsAssignableFrom(t)) .AsSelf() .EnableInterfaceInterceptors() .InterceptedBy(typeof(JobInvocationInterceptor)); // 注册拦截器 builder.RegisterType<JobInvocationInterceptor>(); var container = builder.Build(); // 将Autofac容器与IJobActivator结合 config.JobActivator = new AutofacJobActivator(container);
这个方案适合已经使用Autofac的项目,拦截能力更灵活,甚至可以针对特定Job或方法做精细化控制。
内容的提问来源于stack exchange,提问作者dmarlow
相关产品推荐
相关产品推荐

