Blazor Server中如何在EventCallback执行前调用方法并获取正确服务范围
关于Blazor Server中EventCallback执行前注入服务范围的问题
我的Blazor Server应用包含多个页面,大量使用onclick、onkeypress这类EventCallback,希望在所有这些EventCallback执行前调用一个方法。我查找过ComponentBase,没有找到可重写的对应方法,想知道Blazor Server有没有类似MVC中间件或过滤器的机制。
补充说明
1. 自研AOP组件Rougamo.Fody介绍
我开发了一款编译时AOP组件Rougamo.Fody,功能类似PostSharp,示例代码如下:
// 定义切面类 public class TestAttribute : MoAttribute { public override void OnEntry(MethodContext context) { // OnEntry对应方法执行前 } public override void OnException(MethodContext context) { // OnException对应方法抛出异常后 } public override void OnSuccess(MethodContext context) { // OnSuccess对应方法执行成功后 } public override void OnExit(MethodContext context) { // OnExit对应方法退出时 } } public class TestService { [Test] public async Task MAsync() => await Task.Yield(); [Test] public static void M() { } }
2. 切面访问IServiceProvider的当前方案
近期越来越多用户希望在切面类中访问IServiceProvider,但切面类可应用于静态方法(如上述M方法),无法从目标实例解析IServiceProvider。目前我的解决方案是在创建范围时将IServiceScope存入静态AsyncLocal字段,切面类从此字段获取当前范围:
public class PinnedScope { public static readonly AsyncLocal<IServiceScope?> Scope = new(); } public class TestAttribute : MoAttribute { public override void OnEntry(MethodContext context) { // 从静态字段获取IServiceProvider var serviceProvider = PinnedScope.Scope.Value?.ServiceProvider; } }
3. Blazor Server中的问题
该方案在通用主机、Web API/MVC项目中运行正常,但Blazor Server有所不同:每个SignalR连接都有独立服务范围,页面在此范围内创建,但EventCallback在DefaultHubDispatcher<>.Invoke创建的另一范围内执行。因此在事件回调方法中从PinnedScope.Scope静态字段获取的当前范围,实际是DefaultHubDispatcher<>.Invoke创建的范围,和页面注入的服务提供者不一致。
示例代码:
@page "/counter" @rendermode InteractiveServer @attribute [StreamRendering] <PageTitle>Counter</PageTitle> <h1>Counter</h1> <p role="status">Current count: @currentCount</p> <button class="btn btn-primary" @onclick="IncrementCount">Increase</button> @code { private int currentCount = 0; [Inject] public IServiceProvider Services { get; set; } private async Task IncrementCount() { currentCount++; await Task.Yield(); WhatEver(); } [Test] private static void WhatEver() { } public class TestAttribute : MoAttribute { public override void OnEntry(MethodContext context) { // serviceProvider 和注入的Services不相等 var serviceProvider = PinnedScope.Scope.Value?.ServiceProvider; } } }
我现在需要找到类似中间件或过滤器的方式,在事件回调方法执行前设置PinnedScope.Scope。
内容的提问来源于stack exchange,提问作者Hourglass
相关产品推荐
相关产品推荐

