如何使用Autofac.Extras.DynamicProxy为Blazor组件生命周期实现AOP日志
实现方案
核心原理
Blazor框架提供了IComponentFactory接口作为组件实例的创建入口,替换默认实现后即可自定义组件实例的解析逻辑,完全保留原生Razor组件的编写和引用语法,无需调整原有组件的调用方式。
前置依赖
需提前安装对应Nuget包:
Autofac.Extensions.DependencyInjectionAutofac.Extras.DynamicProxyCastle.Core
步骤1:实现日志拦截器
public class LoggingInterceptor : IInterceptor { private readonly ConcurrentDictionary<Type, ConcurrentDictionary<string, int>> _invokeCounters = new(); public void Intercept(IInvocation invocation) { var componentType = invocation.TargetType; var methodName = invocation.Method.Name; // 统计方法调用次数 var typeCounters = _invokeCounters.GetOrAdd(componentType, _ => new ConcurrentDictionary<string, int>()); var count = typeCounters.AddOrUpdate(methodName, 1, (_, old) => old + 1); // 拼接日志内容,自动获取参数值 var args = string.Join(", ", invocation.Arguments.Select((arg, idx) => $"{invocation.Method.GetParameters()[idx].Name}: {arg}")); Console.WriteLine($"[{count}]{componentType.Name}.{methodName}({args})"); // 执行原有方法逻辑 invocation.Proceed(); } }
步骤2:实现自定义组件工厂
public class AutofacComponentFactory : IComponentFactory { private readonly ILifetimeScope _lifetimeScope; public AutofacComponentFactory(ILifetimeScope lifetimeScope) { _lifetimeScope = lifetimeScope; } public IComponent CreateInstance(IServiceProvider serviceProvider, Type componentType) { // 从Autofac容器解析带代理的组件实例 return (IComponent)_lifetimeScope.Resolve(componentType); } }
步骤3:服务注册配置
public class Program { public static async Task Main(string[] args) { var builder = WebAssemblyHostBuilder.CreateDefault(args); builder.RootComponents.Add<App>("#app"); // 替换Blazor默认的组件工厂 builder.Services.AddScoped<IComponentFactory, AutofacComponentFactory>(); // 接入Autofac容器 builder.Host.UseAutofac(ConfigureContainer); var host = builder.Build(); await host.RunAsync(); } private static void ConfigureContainer(ContainerBuilder builder) { // 注册拦截器 builder.RegisterType<LoggingInterceptor>().AsSelf(); // 注册需要日志埋点的组件,启用动态代理 builder.RegisterType<BasicChild>() .AsSelf() .EnableClassInterceptors() // Blazor组件为类,直接用类代理即可 .InterceptedBy(typeof(LoggingInterceptor)) .InstancePerDependency(); // 保持Blazor组件默认瞬态生命周期 } }
步骤4:清理组件代码
最终组件完全不需要嵌入日志逻辑,保持原生写法即可:
<p>@nameof(BasicChild)</p> <button @onclick="OnClick">StateHasChanged</button> @code { private void OnClick() { StateHasChanged(); } }
效果说明
所有组件的生命周期方法、用户自定义事件方法都会被拦截器自动捕获并输出日志,完全不需要修改组件的调用方式,原生Blazor语法不受任何影响。
内容的提问来源于stack exchange,提问作者ibocon
相关产品推荐
相关产品推荐

