Description
Some non-conforming DI Containers rely on the use of ambient state for providing scoping. This causes a challenge when it comes to integrating with with Blazor due to the way both Blazor and SignalR are set up.
Such container (such as Simple Injector) will have to replace SignalR's default IHubActivator<T>
implementation in order to apply scoping. But even without ambient scoping, non-conformers will likely want to replace the IHubActivator<T>
in order to resolve application hubs. When replacing IHubActivator
, however, there is no way to callback into SignalR's DefaultHubActivator<T>
to resolve framework hubs, such as Blazor's ComponentHub
, as DefaultHubActivator<T>
is internal.
Implementing a custom IHubActivator<T>
likely means choosing one of the following three options:
- Completely reimplement
DefaultHubActivator<T>
's behavior in order to resolve framework types likeComponentHub
- Resolve
ComponentHub
directly from the built-in container - Resolve
ComponentHub
directly from the third-party (non-conforming) container
About these options:
- Option 1 is not desirable because of the amount of code duplication it causes for integration scenarios and the possibly conflicts when the default implementation changes in the future.
- Option 3 is difficult to achieve because
ComponentHub
is an internal type. Neither application code, nor a third-party can access this type and accessing using reflection is brittle as the internal type could change in the future. - Option 2 is currently impossible because
ComponentHub
is not registered in theIServiceCollection
.
There are multiple possible solutions:
- Make SignalR's
DefaultHubActivator<T>
public. This allows the custom activator to create or possibly inject the default activator and call it - Make
ComponentHub
public. This allows an application developer or non-conforming integration package to register it in the application container, or optionally directly into theIServiceCollection
- Register
ComponentHub
into theIServiceCollection
. This allows a custom activator to resolve this type from the framework container without requiringComponentHub
to become public.
I think adding ComponentHub
to the IServiceCollection
is the easiest solution because it doesn't require making any type public, which saves writing and maintaining new documentation. Adding ComponentHub
to the IServiceCollection
is likely a very low-risk operation. The risk of it breaking existing applications presumably is very low.