How to call a method before the EventCallback gets executed

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 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() { }
}

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.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;
    }
}

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.

5

I haven’t gone through all your code [I got a bit lost on the context].

But based on the primary question:

I want to call a method before all these EventCallbacks get executed …….. I haven’t found a method that I could override from ComponentBase.

Here I believe is the answer to that question.

When the Renderer receives an event from the browser it checks if the component implements IHandleEvent. If it does it passes the callback and the event args to

IHandleEvent.HandleEventAsync(EventCallbackWorkItem callback, object? arg)

If it doesn’t it executes the mapped callback directly.

ComponentBase implements IHandleEvent here https://github.com/dotnet/aspnetcore/blob/951b6ead6510409a7847481f818963e696686ca9/src/Components/Components/src/ComponentBase.cs#L349

You can override this in your own base component:

public class MyComponentBase : ComponentBase, IHandleEvent
{
    protected virtual Task OnBeforeHandleEvent(object? arg)
    {
        return Task.CompletedTask;
    }

    async Task IHandleEvent.HandleEventAsync(EventCallbackWorkItem callback, object? arg)
    {
        await this.OnBeforeHandleEvent(arg);

        var task = callback.InvokeAsync(arg);
        var shouldAwaitTask = task.Status != TaskStatus.RanToCompletion && task.Status != TaskStatus.Canceled;

        StateHasChanged();

        if (!shouldAwaitTask)
            return;

        await CallStateHasChangedOnAsyncCompletion(task);
    }

    private async Task CallStateHasChangedOnAsyncCompletion(Task task)
    {
        try
        {
            await task;
        }
        catch // avoiding exception filters for AOT runtime support
        {
            // Ignore exceptions from task cancellations, but don't bother issuing a state change.
            if (task.IsCanceled)
                return;

            throw;
        }

        StateHasChanged();
    }
}

Which you can the use like this:

@page "/counter"
@inherits MyComponentBase

<PageTitle>Counter</PageTitle>

<h1>Counter</h1>

<p role="status">Current count: @currentCount</p>

<button class="btn btn-primary" @onclick="IncrementCount">Click me</button>

@code {
    private int currentCount = 0;

    private void IncrementCount()
    {
        Console.WriteLine("IncrementCount executed");
        currentCount++;
    }
    protected override Task OnBeforeHandleEvent(object? arg)
    {
        // Can detect the type of event based on the args
        Console.WriteLine("OnBeforeHandleEvent executed");
        return Task.CompletedTask;
    }
}

The result is:

info: Microsoft.Hosting.Lifetime[0]
      Content root path: C:UsersshaunsourcereposSO78968957SO78968957
OnBeforeHandleEvent executed
IncrementCount executed

PS

In the below code from your Counter, [StreamRendering] does nothing.

@rendermode InteractiveServer  // Trumps [StreamRendering] 
@attribute [StreamRendering]

1

Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa Dịch vụ tổ chức sự kiện 5 sao Thông tin về chúng tôi Dịch vụ sinh nhật bé trai Dịch vụ sinh nhật bé gái Sự kiện trọn gói Các tiết mục giải trí Dịch vụ bổ trợ Tiệc cưới sang trọng Dịch vụ khai trương Tư vấn tổ chức sự kiện Hình ảnh sự kiện Cập nhật tin tức Liên hệ ngay Thuê chú hề chuyên nghiệp Tiệc tất niên cho công ty Trang trí tiệc cuối năm Tiệc tất niên độc đáo Sinh nhật bé Hải Đăng Sinh nhật đáng yêu bé Khánh Vân Sinh nhật sang trọng Bích Ngân Tiệc sinh nhật bé Thanh Trang Dịch vụ ông già Noel Xiếc thú vui nhộn Biểu diễn xiếc quay đĩa Dịch vụ tổ chức tiệc uy tín Khám phá dịch vụ của chúng tôi Tiệc sinh nhật cho bé trai Trang trí tiệc cho bé gái Gói sự kiện chuyên nghiệp Chương trình giải trí hấp dẫn Dịch vụ hỗ trợ sự kiện Trang trí tiệc cưới đẹp Khởi đầu thành công với khai trương Chuyên gia tư vấn sự kiện Xem ảnh các sự kiện đẹp Tin mới về sự kiện Kết nối với đội ngũ chuyên gia Chú hề vui nhộn cho tiệc sinh nhật Ý tưởng tiệc cuối năm Tất niên độc đáo Trang trí tiệc hiện đại Tổ chức sinh nhật cho Hải Đăng Sinh nhật độc quyền Khánh Vân Phong cách tiệc Bích Ngân Trang trí tiệc bé Thanh Trang Thuê dịch vụ ông già Noel chuyên nghiệp Xem xiếc khỉ đặc sắc Xiếc quay đĩa thú vị
Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa
Thiết kế website Thiết kế website Thiết kế website Cách kháng tài khoản quảng cáo Mua bán Fanpage Facebook Dịch vụ SEO Tổ chức sinh nhật