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 like ComponentHub
- 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 the IServiceCollection.
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 the IServiceCollection
- Register
ComponentHub into the IServiceCollection. This allows a custom activator to resolve this type from the framework container without requiring ComponentHub 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.
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 theIHubActivator<T>in order to resolve application hubs. When replacingIHubActivator, however, there is no way to callback into SignalR'sDefaultHubActivator<T>to resolve framework hubs, such as Blazor'sComponentHub, asDefaultHubActivator<T>is internal.Implementing a custom
IHubActivator<T>likely means choosing one of the following three options:DefaultHubActivator<T>'s behavior in order to resolve framework types likeComponentHubComponentHubdirectly from the built-in containerComponentHubdirectly from the third-party (non-conforming) containerAbout these options:
ComponentHubis 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.ComponentHubis not registered in theIServiceCollection.There are multiple possible solutions:
DefaultHubActivator<T>public. This allows the custom activator to create or possibly inject the default activator and call itComponentHubpublic. This allows an application developer or non-conforming integration package to register it in the application container, or optionally directly into theIServiceCollectionComponentHubinto theIServiceCollection. This allows a custom activator to resolve this type from the framework container without requiringComponentHubto become public.I think adding
ComponentHubto theIServiceCollectionis the easiest solution because it doesn't require making any type public, which saves writing and maintaining new documentation. AddingComponentHubto theIServiceCollectionis likely a very low-risk operation. The risk of it breaking existing applications presumably is very low.