我的 Blazor 服务器应用程序有许多页面和许多EventCallback
诸如onclick
、onkeypress
等等。我想在执行所有这些 EventCallbacks 之前调用一个方法。
我还没有找到可以从中覆盖的方法ComponentBase
。或者 Blazor 服务器中是否有类似 MVC 的中间件或过滤器?
编辑
我编写了一个编译时 AOP 组件Rougamo.Fody,类似于 PostSharp。
// define an aspect class
public class TestAttribute : MoAttribute
{
public override void OnEntry(MethodContext context)
{
// OnEntry corresponds to before method execution
}
public override void OnException(MethodContext context)
{
// OnException corresponds to after method throws an exception
}
public override void OnSuccess(MethodContext context)
{
// OnSuccess corresponds to after method execution successfully
}
public override void OnExit(MethodContext context)
{
// OnExit corresponds to when method exits
}
}
public class TestService
{
[Test]
public async Task MAsync() => await Task.Yield();
[Test]
public static void M() { }
}
最近,越来越多的人要求访问IServiceProvider
方面类。但是方面类可以应用于静态方法(如上面的方法) ,所以我无法从目标实例(如上面的类的实例)M
解析。IServiceProvider
TestService
目前我的解决方案是在创建作用域时将其保存IServiceScope
到静态AsyncLocal
字段中。现在,您可以从方面类中的静态字段中获取当前作用域。
// For the full implementation: https://github.com/inversionhourglass/DependencyInjection.StaticAccessor/blob/master/src/DependencyInjection.StaticAccessor/PinnedScope.cs
public class PinnedScope
{
public static readonly AsyncLocal<IServiceScope?> Scope = new();
}
public class TestAttribute : MoAttribute
{
public override void OnEntry(MethodContext context)
{
// get IServiceProvider from the static field
var serviceProvider = PinnedScope.Scope.Value?.ServiceProvider;
}
}
它在通用主机和 Web API / MVC 项目中运行良好,但 Blazor 服务器不同。每个 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 is not equal to the injected property Services
var serviceProvider = PinnedScope.Scope.Value?.ServiceProvider;
}
}
}`
我正在尝试寻找一种方法,例如中间件或过滤器,在PinnedScope.Scope
事件回调方法执行之前进行设置。
我还没有看完你的所有代码[我对上下文有点迷茫]。
但基于主要问题:
我相信这就是这个问题的答案。
当渲染器从浏览器收到事件时,它会检查组件是否实现了
IHandleEvent
。如果实现了,它会将回调和事件参数传递给如果没有,则直接执行映射的回调。
ComponentBase
IHandleEvent
在这里实现https://github.com/dotnet/aspnetcore/blob/951b6ead6510409a7847481f818963e696686ca9/src/Components/Components/src/ComponentBase.cs#L349您可以在自己的基本组件中覆盖它:
你可以像这样使用:
结果是:
附言
在下面的代码中
Counter
,[StreamRendering]
不执行任何操作。