Search code examples
dependency-injectionsignalrorleans

SignalR with orleans how to pass SignalR from startup to grain


I am very new with orleans and trying to grasp everything with grains and so forth.

What i got is that in my startup.cs file i add the SignalR like this

public IServiceProvider ConfigureServices(IServiceCollection services)
    {

        Program.WriteConsole("Adding singletons");
        services
            .AddSingleton(achievementManager)
            .AddMvc();
        services.AddSingleton(SignalRClient);

        return services.BuildServiceProvider();
    }

So far everything is fine i can start my host/application and it connects to SignalR as it should. But what i cant wrap my head around is how do i get this down to my grain? if i had a controller i would simply send it down in the constructor on startup but how do i do this with a grain? Or can i even do it like this. Any guidance is appreciated.

In the grain then i want to do something like this

[StatelessWorker]
[Reentrant]
public class NotifierGrain : Grain, INotifierGrain
{
    private HubConnection SignalRClient { get; }

    public NotifierGrain(HubConnection signalRClient)
    {
        SignalRClient = signalRClient;
        SignalRClient.SendAsync(Methods.RegisterService, Constants.ServiceName);
    }

    public Task NotifyClients(object message, MessageType type)
    {

            var registerUserNotification = (RegisterUserNotificationModel)message;
                SignalRClient.SendAsync(Methods.RegisterUserToMultipleGroups, registerUserNotification.UserId, registerUserNotification.InfoIds);
        }

        return Task.CompletedTask;
    }

Then i try to call the Notify method from another grain like this

var notifier = GrainFactory.GetGrain<INotifierGrain>(Constants.NotifierGrain);
        await notifier.NotifyClients(notification, MessageType.RegisterUser);

But trying to do this ends up with an error like this

InvalidOperationException: Unable to resolve service for type 'Microsoft.AspNetCore.SignalR.Client.HubConnection' while attempting to activate 'User.Implementation.Grains.NotifierGrain'.

Solution

  • Orleans supports constructor injection, so you can inject the SignalRClient into your grain constructor. In your code you are already correctly registering the client using services.AddSingleton(SignalRClient), so I will focus on how to inject the type into your grain.

    I do not know what the type the SignalR client object is, but in this example I assume that the type is "SignalRClient":

    [StatelessWorker]
    [Reentrant]
    public class NotifierGrain : Grain, INotifierGrain
    {
        private readonly SignalRClient signalRClient;
    
        public NotifierGrain(SignalRClient signalRClient)
        {
            this.signalRClient = signalRClient;
        }
    
        public async Task NotifyClients(object message, MessageType type)
        {
            var registerUserNotification = (RegisterUserNotificationModel)message;
            await this.signalRClient.SendAsync(
                MessageMethods.RegisterUserToMultipleGroups,
                registerUserNotification.UserId,
                registerUserNotification.infoIds);
        }
    }