You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.18 17:35:16