-
Notifications
You must be signed in to change notification settings - Fork 10.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Intercepting Blazor page events. #30115
Comments
@dotnetjunkie thanks for contacting us. Is this achievable with a Hub filter? |
/cc @BrennanConroy |
Unless I'm misunderstanding the issue, Hub filters wont help. They are already using the
I don't know where this happens, but is there a scope being created by Blazor that isn't easily hooked into? This seems to be the ask. |
@BrennanConroy isn't it the case that hubfilters allow you to intercept each message a hub receives? Unless I'm missing something about how this works, my understanding is that it should enable you to intercept the messages from the browser and run code at that point, which means they should be able to setup/restore their own scopes there? That said, while I think this is possible I'm not very confortable with it, since it plugs into what we consider to be an implementation detail of how Blazor server operates. For example, if we decide to change the messages that we send, I believe a solution like this would break. |
Hi @javiercn, @BrennanConroy is correct. An
DI Containers like Simple Injector can't replace the built-in MS.DI Container and have to live side-by-side. This means that the need to start their own To prevent confusion for Blazor users, however, a Simple Injector I created a proof of concept for Simple Injector users here. In short, that PoC does the following: // ScopeAccessor is a class from the PoC. ScopeAccessor allows storing
// the Simple Injector scope in the MS.DI IServiceScope state.
var accessor = requestServices.GetRequiredService<ScopeAccessor>();
if (accessor.Scope is null)
{
// This instructs Simple Injector to create a new Scope
accessor.Scope = AsyncScopedLifestyle.BeginScope(container);
// This stores the MS.DI IServiceScope inside the Simple Injector scope
accessor.Scope.GetInstance<ServiceScopeAccessor>().Scope = (IServiceScope)requestServices;
}
else
{
// This instructs Simple Injector to set the scope pulled in from IServiceScope
// as the current scope for the active (asynchronous) context. (stored inside a AsyncLocal<Scope>)
lifestyle.SetCurrentScope(accessor.Scope);
} In the PoC, this code is triggered by some infrastructure to the proper Blazor interception points (currently But the problem seems that there is no proper interception point that is triggered right before a Blazor event goes off in such way that when this interception points sets a value in a |
@dotnetjunkie thanks for the additional details. I think I have a better grasp of what's going on here now. Have you tried setting up the scope on a circuit handler instead of using the hub activator? Blazor creates its own scope and circuit handlers run inside that scope context. I think that + async local might be enough for this to work. What I think would happen is that you resolve the servicescopeaccessor at that point and set it to your custom scope there. From there I think things would flow "automagically" to other areas? I'm speculating quite a bit here BTW, this code is complicated and deals with a synchronization context and stuff, which always makes things more fun. As I mentioned, I think you might be set if you do this inside a circuit handler, so it's worth giving it a shot. |
Just checked, but the circuit handlers don't go off before the Blazor events; the seem to only get invoked when the connections go up and down, but not in between. |
@dotnetjunkie I was suggesting that maybe by setting it up when the circuit is started the async local would do the magic for the rest of the circuit. Otherwise we need an additional primitive to plug in at the event and JS interop levels. |
Could you show me an example? |
Then register it on DI with |
@javiercn, thank you for your example. Unfortunately, async local doesn't do "the magic" for the rest of the circuit; the scope of async local ends rather quickly. Your solution, unfortunately, doensn't work. |
@dotnetjunkie I see. I'm going to move this so that we can discuss within the team. |
Thanks for contacting us. |
We've moved this issue to the Backlog milestone. This means that it is not going to be worked on for the coming release. We will reassess the backlog following the current release and consider this item at that time. To learn more about our issue management process and to have better expectation regarding different types of issues you can read our Triage Process. |
Interesting, this is the most often asked question (and probably most requested feature) on my youtube channel. Got 180,000 hits in Google. And it's backlogged. |
@beefydog if you can point us to the data, it would help us to prioritize this issue, but we haven't seen that interest reflected here. |
Would also like to have this. If you could intercept all delegates (or their invocations) that get passed to EventCallbackFactory you could do things like structured exception handling or advanced logging or other aspects. Right now you need to boilerplate everything that needs to go in every event handler. :-/ |
To solve this in a local project (not a solution for frameworks) you can use Castle.DynamicProxy / IInterceptor together with an custom implementation of IComponentFactory. Never the less - it would be much easier and more performant if there would be inbuild support to do sth like this. |
Needed sth like this - you can implement it if you combine a SignalR IHubFilter together with a CircuitHandler. The HubFilter can control the AsyncLocal and put something like a value holder in InvokeMethodAsync and the CircuitHandler can access the circuit scope and other things and write it into your value holder. The values can than be read back and cached in your HubFilter so you can restore them in the next run. Only keep in mind that the cleaning of your cached values must be done by OnCircuitClosedAsync because instances can reconnect. And if u use the SignalR connection id to correlate that you need to handle the change in OnConnectionUp/OnConnectionDown in case of a reconnect. |
We believe this was addressed as part of #46968, if you still run into issues with this approach, please let us know. |
Sorry if I'm missing something, but the original request was "... I'm looking for a mechanism that allows intercepting calls those 'code behind' methods... " also mentioned here: #30115 (comment) However, the issue linked above appears to be for circuits (i.e., Blazor Server) only? |
In addition to @FlukeFan's response, I already mentioned above that circuit breakers won't solve the issue, except when #46968 chances what can be intercepted? |
I also cannot see this closed. The implementation tackles only the connection aspect and not the event interception. |
Blazor supports the notion of events, such as
@onlick
events, as shown here:This allows the
DeleteUser
method to be invoked in the page's@code
section.I'm looking for a mechanism that allows intercepting calls those 'code behind' methods, in order to be able to execute some infrastructure logic right before the method is invoked. If such mechanism is currently missing, I would urge the addition of a feature that makes this possible.
This question/discussion is related to my earlier issues #19642 and #29194 because I'm trying to find ways to integrate non-conforming DI Containers (such as Simple Injector) with the Blazor pipeline. As non-conforming containers don't replace the built-in DI Container, but merely live side-by-side, it is important to be able to start or continue a non-conforming container's Scope at the proper time.
Starting and continuing an existing scope can be done partially by:
IComponentActivator
) to start/continue a scopeIHubActivator<T>
) to start/continue a scopeThis unfortunately leaves us with the invocation of Blazor events. When they are invoked, neither the
IComponentActivator
norIHubActivator<T>
is called, which causes that code to be executed outside the context of a non-conforming container's scope.I might have overlooked the proper interception point for this in the Blazor code base. If there is such an interception point, please let me know. If there isn't, I would like to see it added.
The text was updated successfully, but these errors were encountered: