4
votes

I want to inject a singleton controller into my hubs using Simple Injector.

I've already tried the following but I'm getting status 500 as response now.

Hub code:

public class EventDataHub : Hub
    {
        private static IEventDataController _dataController;

        public EventDataHub(IEventDataController dataController)
        {
            _dataController = dataController;
        }

        public void Subscribe(string signal)
        {
            _dataController.Subscribe(signal, Context.ConnectionId);
        }
    }

Startup.cs

public class Startup
    {
        public void Configuration(IAppBuilder app)
        {

            var container = new Container();

            var hybridLifestyle = Lifestyle.CreateHybrid(
                lifestyleSelector: () => HttpContext.Current != null,
                trueLifestyle: new WebRequestLifestyle(),
                falseLifestyle: new LifetimeScopeLifestyle());

            container.Register<IEventDataController, EventDataController>(Lifestyle.Singleton);
            container.Register<IHub, EventDataHub>(hybridLifestyle);

            container.Verify();

            var activator = new SimpleInjectorHubActivator(container);
            GlobalHost.DependencyResolver.Register(typeof(IHubActivator), () => activator);

            app.MapSignalR();
        }
    }

Hub activator

public class SimpleInjectorHubActivator : IHubActivator
    {
        private readonly Container _container;

        public SimpleInjectorHubActivator(Container container)
        {
            _container = container;
        }

        public IHub Create(HubDescriptor descriptor)
        {
            return (IHub)_container.GetInstance(descriptor.HubType);
        }
    }

The Subscribe method seems to be unreachable from the client side. The hub constructor is executed.

Exception stack:

[MissingMethodException: no parameterless constructor defined for this object]
System.RuntimeTypeHandle.CreateInstance(RuntimeType type, Boolean publicOnly, Boolean noCheck, Boolean& canBeCached, RuntimeMethodHandleInternal& ctor, Boolean& bNeedSecurityCheck) +0
System.RuntimeType.CreateInstanceSlow(Boolean publicOnly, Boolean skipCheckThis, Boolean fillCache, StackCrawlMark& stackMark) +113
System.RuntimeType.CreateInstanceDefaultCtor(Boolean publicOnly, Boolean skipCheckThis, Boolean fillCache, StackCrawlMark& stackMark) +206 System.Activator.CreateInstance(Type type, Boolean nonPublic) +83 System.Activator.CreateInstance(Type type) +11 Microsoft.AspNet.SignalR.Hubs.DefaultHubActivator.Create(HubDescriptor descriptor) +84
Microsoft.AspNet.SignalR.Hubs.DefaultHubManager.ResolveHub(String hubName) +27
Microsoft.AspNet.SignalR.Hubs.HubDispatcher.CreateHub(IRequest request, HubDescriptor descriptor, String connectionId, StateChangeTracker tracker, Boolean throwIfFailedToCreate) +386
Microsoft.AspNet.SignalR.Hubs.HubDispatcher.OnReceived(IRequest request, String connectionId, String data) +400
Microsoft.AspNet.SignalR.<>c__DisplayClass64_1.b__5() +34 Microsoft.AspNet.SignalR.TaskAsyncHelper.FromMethod(Func`1 func) +28
System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) +92
System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) +58
Microsoft.AspNet.SignalR.Transports.d__40.MoveNext() +742 System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) +92
System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) +58 Microsoft.Owin.Mapping.d__0.MoveNext() +385
System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) +92
System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) +58
Microsoft.Owin.Host.SystemWeb.IntegratedPipeline.d__5.MoveNext() +187 System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) +92
System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) +58
Microsoft.Owin.Host.SystemWeb.IntegratedPipeline.d__2.MoveNext() +185 Microsoft.Owin.Host.SystemWeb.IntegratedPipeline.StageAsyncResult.End(IAsyncResult ar) +69
Microsoft.Owin.Host.SystemWeb.IntegratedPipeline.IntegratedPipelineContext.EndFinalWork(IAsyncResult ar) +64
System.Web.AsyncEventExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() +380 System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously) +155

Edit:

Moving the DI configuration from Startup.cs to global.asax throws this exception:

[ArgumentNullException: value cannot be null. Parametername: s] System.IO.StringReader..ctor(String s) +11377176
Microsoft.AspNet.SignalR.Json.JsonSerializerExtensions.Parse(JsonSerializer serializer, String json) +63
Microsoft.AspNet.SignalR.Hubs.HubRequestParser.Parse(String data, JsonSerializer serializer) +21
Microsoft.AspNet.SignalR.Hubs.HubDispatcher.OnReceived(IRequest request, String connectionId, String data) +40
Microsoft.AspNet.SignalR.<>c__DisplayClass64_1.b__5() +34 Microsoft.AspNet.SignalR.TaskAsyncHelper.FromMethod(Func`1 func) +28
System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) +92
System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) +58
Microsoft.AspNet.SignalR.Transports.d__40.MoveNext() +742 System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) +92
System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) +58 Microsoft.Owin.Mapping.d__0.MoveNext() +385
System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) +92
System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) +58
Microsoft.Owin.Host.SystemWeb.IntegratedPipeline.d__5.MoveNext() +187 System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) +92
System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) +58
Microsoft.Owin.Host.SystemWeb.IntegratedPipeline.d__2.MoveNext() +185 Microsoft.Owin.Host.SystemWeb.IntegratedPipeline.StageAsyncResult.End(IAsyncResult ar) +69
Microsoft.Owin.Host.SystemWeb.IntegratedPipeline.IntegratedPipelineContext.EndFinalWork(IAsyncResult ar) +65
System.Web.AsyncEventExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() +380 System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously) +155

1
Please find the raised exception and show all the details of this exception in your question.Steven
The SignalR application doesn't crash. The exception stack I've included is inside the 500 response.gerric
From the stacktrace it becomes clear that SignalR is using its DefaultHubActivator instead of your SimpleInjectorHubActivator.Steven
Please take a look at this discussion to find out how to integrate Simple Injector with SignalR.Steven
I have difficulties extracting the concluded information. Is it really necessary to implement SimpleInjectorHubDispatcher? Why is registering the custom activator not working?gerric

1 Answers

3
votes

I finally found the problem:

container.Verify() is breaking the registration of the IHubActivator. So it has to be called either afterwards, or never.

Additionally I removed the container registration for IHub, as it works without now. (I added it because container.Register<IEventDataController, EventDataController>(Lifestyle.Singleton) wasn't working at that time and that fixed it somehow)

So my final code in Startup.cs looks like this:

public void Configuration(IAppBuilder app)
{
    var container = new Container();

    container.Register<IEventDataController, EventDataController>(Lifestyle.Singleton);

    var activator = new SimpleInjectorHubActivator(container);
    GlobalHost.DependencyResolver.Register(typeof(IHubActivator), () => activator);

    app.MapSignalR();
}