Skip to content
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

SimpleInjector SignalR Core integration throws SimpleInjector.ActivationException on LongPolling #630

Closed
NimaAra opened this issue Nov 4, 2018 · 5 comments
Labels

Comments

@NimaAra
Copy link

NimaAra commented Nov 4, 2018

I have been using the integration sample suggested in #232 to integrate SimpleInjector with SignalR Core.

Everything works as expected until the protocol is set to LongPolling where the following exception is thrown:

SimpleInjector.ActivationException: 'The MyHub is registered as 'Async Scoped' lifestyle, but the instance is requested outside the context of an active (Async Scoped) scope.'

I have put together a server and client example where it can be reproduced.

If you change the protocol at THIS line to LongPolling, you will see the exception thrown.

.WithUrl(ENDPOINT, o => o.Transports = HttpTransportType.LongPolling)

The SimpleInjector integration methods can found in SimpleInjectorHelper.

@dotnetjunkie
Copy link
Collaborator

Can you post a full stack trace?

@NimaAra
Copy link
Author

NimaAra commented Nov 4, 2018

Sure:

   at SimpleInjector.Scope.GetScopelessInstance[TImplementation](ScopedRegistration`1 registration)
   at SimpleInjector.Advanced.Internal.LazyScopedRegistration`1.GetInstance(Scope scope)
   at lambda_method(Closure )
   at SimpleInjector.InstanceProducer.GetInstance()
   at SimpleInjector.Container.GetInstance[TService]()
   at SignalR.Sample.Server.SimpleInjectorHelper.SimpleInjectorHubActivator`1.Create() in D:\My Code\GitHub\SignalR.Sample\SignalR.Sample.Server\SimpleInjectorExtensions.cs:line 36
   at Microsoft.AspNetCore.SignalR.Internal.DefaultHubDispatcher`1.OnConnectedAsync(HubConnectionContext connection)

@dotnetjunkie
Copy link
Collaborator

In your case, you need to implement a custom HubDispatcher<T>, because SignalR's default hub dispatcher is in control of managing scopes. Unfortunately, SignalR Core didn't really learn from the past, so this is actually more complicated than it should. But eitherway, you can use this implementation:

private sealed class SimpleInjectorScopeHubDispatcher<THub> : HubDispatcher<THub> where THub : Hub
{
    private readonly Container container;
    private readonly HubDispatcher<THub> decorated;

    public SimpleInjectorScopeHubDispatcher(Container container, DefaultHubDispatcher<THub> decorated)
    {
        this.container = container;
        this.decorated = decorated;
    }

    public override async Task DispatchMessageAsync(HubConnectionContext connection, HubMessage hubMessage)
    {
        using (this.BeginScope()) await this.decorated.DispatchMessageAsync(connection, hubMessage);
    }

    public override async Task OnConnectedAsync(HubConnectionContext connection)
    {
        using (this.BeginScope()) await this.decorated.OnConnectedAsync(connection);
    }

    public override async Task OnDisconnectedAsync(HubConnectionContext connection, Exception exception)
    {
        using (this.BeginScope()) await this.decorated.OnDisconnectedAsync(connection, exception);
    }

    public override IReadOnlyList<Type> GetParameterTypes(string name) => this.decorated.GetParameterTypes(name);
    public override Type GetReturnType(string invocationId) => this.decorated.GetReturnType(invocationId);
    private Scope BeginScope() => AsyncScopedLifestyle.BeginScope(this.container);
}

Using this class, your Simple Injector/SignalR configuration will look as follows.

services.AddSingleton(typeof(IHubActivator<>), typeof(SimpleInjectorHubActivator<>));
services.AddSingleton(typeof(DefaultHubDispatcher<>));
services.AddSingleton(typeof(HubDispatcher<>), typeof(SimpleInjectorScopeHubDispatcher<>));

@NimaAra
Copy link
Author

NimaAra commented Nov 4, 2018

Excellent, works great! Thanks for the quick reply.

@dotnetjunkie
Copy link
Collaborator

The introduction of Simple Injector v4.9 simplified the integration with SignalR Core. I updated the SignalR Core integration page accordingly. The described integration also fixes the long-polling problems.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants