Skip to content

Instantly share code, notes, and snippets.

@gertjvr
Last active August 4, 2023 06:56
Show Gist options
  • Save gertjvr/9968dd14e298528e875f7e7f47511731 to your computer and use it in GitHub Desktop.
Save gertjvr/9968dd14e298528e875f7e7f47511731 to your computer and use it in GitHub Desktop.
Autofac.SignalR hub scoped dependencies per instance.

SignalR generates a hub for each method invoke ie onConnected, onDisconnect or any other methods on the hub. Autofac.SignalR all hub dependencies are resolved from the root container making them singletons.

I did find another solutions https://github.com/lethek/SignalR.Extras.Autofac but this required inheriting from a special lifetimehub, retro fitting this into an large existing solution would take a lot of work an re-testing.

The solutions below allows you to scope all dependencies per hub instance.

  • Install-Package Autofac.SignalR
  • Install-Package Castle.Core
public static class RegistrationExtensions
{
    public static IRegistrationBuilder<object, ScanningActivatorData, DynamicRegistrationStyle> RegisterHubActivator(this ContainerBuilder builder, params Assembly[] assemblies)
    {
        return builder.RegisterType<AutofacHubActivator>().As<IHubActivator>().SingleInstance();
    }
}

public class AutofacHubActivator : IHubActivator
{
    private readonly ILifetimeScope _lifetimeScope;

    public AutofacHubActivator(ILifetimeScope lifetimeScope)
    {
        _lifetimeScope = lifetimeScope;
    }

    public IHub Create(HubDescriptor descriptor)
    {
        var scope = _lifetimeScope.BeginLifetimeScope();
        var hubType = descriptor.HubType;

        var constructor = hubType.GetConstructors()
            .Select(c => new { c, idx = c.GetParameters().Length })
            .OrderByDescending(x => x.idx).Select(x => x.c)
            .First();

        var parameters = constructor.GetParameters().Select(parameterInfo => scope.Resolve(parameterInfo.ParameterType)).ToArray();

        var generator = new ProxyGenerator();
        return generator.CreateClassProxy(descriptor.HubType, ProxyGenerationOptions.Default, parameters, new DisposeInterceptor(scope)) as IHub;
    }
}

public class DisposeInterceptor : StandardInterceptor
{
    private readonly ILifetimeScope _lifetimeScope;

    public DisposeInterceptor(ILifetimeScope lifetimeScope)
    {
        _lifetimeScope = lifetimeScope;
    }

    protected override void PostProceed(IInvocation invocation)
    {
        if (invocation.Method.Name == "Dispose")
        {
            _lifetimeScope.Dispose();
        }

        base.PostProceed(invocation);
    }
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment