Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Invoking SignalR Hub not working for Asp.Net Core Web API

I'm a newb to SignalR. I'm trying to set up a Asp.Net Core WebAPI so that other clients can connect to it using SignalR and get real-time data. My Hub class is:

public class TimeHub : Hub
{
    public async Task UpdateTime(string message)
    {
        await Clients.All.SendAsync("ReceiveMessage", message);
    }
}

I have a relay class as follows:

public class TimeRelay : ITimeRelay
{
    private readonly IHubContext<TimeHub> _timeHubContext;

    public TimeRelay(IHubContext<TimeHub> context)
    {

        _timeHubContext = context;
        Task.Factory.StartNew(async () =>
        {
            while (true)
            {
                await context.Clients.All.SendAsync("UpdateTime", DateTime.Now.ToShortDateString());
                Thread.Sleep(2000);
            }
        });
    }
}

Startup class:

public void ConfigureServices(IServiceCollection services)
{
    services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);

    services.AddSignalR();
}

public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
    app.UseDeveloperExceptionPage();

    app.UseHttpsRedirection();

    app.UseSignalR((x) =>
    {
        x.MapHub<TimeHub>("/timeHub");
    });
    app.UseMvc();
}

The client is a console application and the code is:

class Program
{    
    static Action<string> OnReceivedAction = OnReceived;

    static void Main(string[] args)
    {
        Connect();
        Console.ReadLine();
    }

    private static async void Connect()
    {
        var hubConnectionBuilder = new HubConnectionBuilder();

        var hubConnection = hubConnectionBuilder.WithUrl("http://localhost:60211/timeHub").Build();

        await hubConnection.StartAsync();

        var on = hubConnection.On("ReceiveMessage", OnReceivedAction);

        Console.ReadLine();    
        on.Dispose();
        await hubConnection.StopAsync();
    }

    static void OnReceived(string message)
    {
        System.Console.WriteLine($"{message}");
    }
}

I tried debugging the application. The client got connected to the TimeHub succesfully. The no of connections in Clients.All changed from 0 to 1, when the client got connected. But, when await context.Clients.All.SendAsync("UpdateTime", DateTime.Now.ToShortDateString()); is executed, the UpdateTime function in TimeHub is not getting executed and the client is not getting any message.

I tried using "UpdateTime", "SendMessage", and "ReceiveMessage" as method in Clients.All.SendAsync in TimeRelay class. Nothing worked. Could someone point out my mistake in this.

like image 495
Alen Alex Avatar asked Aug 22 '18 13:08

Alen Alex


2 Answers

For Clients, it will be null if there is no client connecting to server. For starting Asp.Net Core SignalR and Console App at the same time, the Clients may be null since Index may be called before Console App connects the signalR server.

Try steps below:

  1. Change TimeHub

    public class TimeHub: Hub
    {
    public async Task UpdateTime(string message)
    {
        if (Clients != null)
        {
            await Clients.All.SendAsync("ReceiveMessage", message);
        }
    }
    }
    
  2. Register TimeHub

     services.AddSingleton<TimeHub>();  
    
  3. Controller

     public class HomeController : Controller
    {
    private readonly TimeHub _timeHub;
    public HomeController(TimeHub timeHub)
    {
        _timeHub = timeHub;
    }
    public IActionResult Index()
    {
        Task.Factory.StartNew(async () =>
        {
            while (true)
            {
                try
                {
                    await _timeHub.UpdateTime(DateTime.Now.ToShortDateString());
                    Thread.Sleep(2000);
                }
                catch (Exception ex)
                {
    
                }
            }
        });
        return View();
    }
    
like image 183
Edward Avatar answered Nov 03 '22 04:11

Edward


I got it to work and thought I will answer it here. Thanks @TaoZhou for the tip.

My mistake was sending "UpdateTime" from server and waiting on "ReceiveMessage" at the client.

Ideally the code should look like the following:

SignalR Server:
await context.Clients.All.SendAsync("UpdateTime", DateTime.Now.ToShortDateString());

SignalR Client:
var on = hubConnection.On("UpdateTime", OnReceivedAction);

In this case any message send from the server would be received at the client instantly.
Please refer the code provided in the question for more info.

like image 33
Alen Alex Avatar answered Nov 03 '22 04:11

Alen Alex