3

I can't seem to the following code working. All I'm doing is in ConfigureServies calling _serviceProvider.GetService<IConnectionManager>(); and saving it in a static field and trying to use it later to get access to a IConnectionManager and subsequently call GetHubContext<MyHub> so I can broadcast messages to all connected clients.

_connectionManager.GetHubContext<MyHub>().Clients.All.doSomethingOnClients();

Just as a test, the same line of code inside a webapi controller action method works fine! (with IConnectionManager injected via constructor). That makes me believe my signalr set up is just fine, just how I got things in the startup class is wrong somewhere. GetHashCode on the IConnectionManager in startup and my controller gives different hash codes. I just need to hook things up on the ApplicationLifetime OnStartUp ...

Can you help me understand where things are going wrong please?

public class Startup
{
    public static IServiceProvider _serviceProvider;
    public static IConnectionManager _connectionManager;
    private readonly IHostingEnvironment _hostingEnv;
    public IConfigurationRoot Configuration { get; }

    public Startup (IHostingEnvironment env)
    {
        // ...
    }
    public void ConfigureServices (IServiceCollection services)
    {               
        // ....
        services.AddSignalR(options => {
            options.Hubs.EnableDetailedErrors = true;
        });

        services.AddMvc();
        // ...
        _serviceProvider = services.BuildServiceProvider();
        _connectionManager = _serviceProvider.GetService<IConnectionManager>();
    }

    public void Configure (IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory, IApplicationLifetime applicationLifetime)
    {
        // ...
        applicationLifetime.ApplicationStarted.Register(OnStartUp);
        // ...
        app.UseMvc(routes => {
            routes.MapRoute("default", "{controller=Home}/{action=Index}/{id?}");
        });
        app.UseSignalR();
        // ...
    }

    public void OnStartUp ()
    {
        var x = _serviceProvider.GetService<MySingletonObject>();
        // MySingletonObject has a  VersionUpdated event handler
        x.VersionUpdated += OnUpdate;
    }

    private void OnUpdate (object sender, EventArgs e)
    {

         // I get here everytime my singleton gets updated fine!
         // but the following does not work  
        _connectionManager.GetHubContext<MyHub>().Clients.All.doSomethingOnClients();    
    }

}

I am using "Microsoft.AspNetCore.SignalR.Server/0.2.0-alpha1-22362".

Søren
  • 6,517
  • 6
  • 43
  • 47
salek
  • 444
  • 4
  • 14
  • [How to get SignalR Hub Context in a ASP.NET Core](https://stackoverflow.com/a/46319153/428061) – Søren Sep 20 '17 at 10:09

1 Answers1

4

1st thing is to realize this version of SignalR isn't shipping, it's just alpha. The problem you're having is because you're building 2 service providers and they're not talking to each other. You call BuildServiceProvider() instead of injecting the IConnectionManager into your Configure method. You can also clean up a lot of the service locator pattern by injecting dependencies directly into configure and then using them in the callbacks.

public class Startup
{
    public IConfigurationRoot Configuration { get; }

    public Startup (IHostingEnvironment env)
    {
        // ...
    }

    public void ConfigureServices (IServiceCollection services)
    {               
        // ....
        services.AddSignalR(options => {
            options.Hubs.EnableDetailedErrors = true;
        });

        services.AddMvc();
        // ...
    }

    public void Configure (IApplicationBuilder app, 
                        IHostingEnvironment env, 
                        ILoggerFactory loggerFactory, 
                        IApplicationLifetime applicationLifetime,
                        MySingletonObject obj,
                        IHubContext<MyHub> context)
    {
        // ...
        applicationLifetime.ApplicationStarted.Register(() => OnStartUp(obj, context));
        // ...
        app.UseMvc(routes => {
            routes.MapRoute("default", "{controller=Home}/{action=Index}/{id?}");
        });
        app.UseSignalR();
        // ...
    }

    public void OnStartUp(MySingletonObject obj, IHubContext<MyHub> context)
    {
        // MySingletonObject has a  VersionUpdated event handler
        obj.VersionUpdated += (sender, e) => 
        {
            context.Clients.All.doSomethingOnClients();
        };
    }

}

Even cleaner would be a another service that would compose everything so you don't end up with so many arguments in your startup method.

Søren
  • 6,517
  • 6
  • 43
  • 47
davidfowl
  • 37,120
  • 7
  • 93
  • 103
  • Thanks a lot David, really appreciate your answer, Thanks for the code review, I forgot I could inject anything to the Configure method. It's working just fine now! – salek Oct 16 '16 at 09:36
  • I am just injecting IHubContext into my controllers to use. Seems to work fine. Thanks for the tip. – Anton Swanevelder Jun 11 '18 at 10:43