My Blazor server application has many pages and many EventCallbacks like onclick, onkeypress, etc. I want to call a method before all these EventCallbacks get executed.
I haven't found a method that I could override from ComponentBase. Or is there any middleware or filter like in MVC in Blazor server?
Edit
I have written a compile-time AOP component, Rougamo.Fody, similar to PostSharp.
// define an aspect classpublic 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() { }}Recently, more and more people have been asking for access to IServiceProvider in the aspect class. But the aspect class could be applied to a static method like the method M above, so I cannot resolve the IServiceProvider from the target instance, like the instance of the class TestService above.
Currently, my solution is to save the IServiceScope into a static AsyncLocal field when creating a scope. Now, you can get the current scope from the static field in the aspect class.
// For the full implementation: https://github.com/inversionhourglass/DependencyInjection.StaticAccessor/blob/master/src/DependencyInjection.StaticAccessor/PinnedScope.cspublic 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; }}It works fine in generic host and Web API / MVC projects, but Blazor server is different. Each SignalR connection has its own service scope, and the pages are created within this scope. But the EventCallBack executes in another scope that is created in DefaultHubDispatcher<>.Invoke. So when I try to get the current scope from the static field PinnedScope.Scope in the event callback method, it actually returns the scope that DefaultHubDispatcher<>.Invoke created.
@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; } }}` I'm trying to find a way, like middleware or a filter, to set the PinnedScope.Scope before the event callback method executes.