Home > Back-end >  SignalR callback seems not firing in ASP.NET Core 6 Web API with .NET 6 Winforms client
SignalR callback seems not firing in ASP.NET Core 6 Web API with .NET 6 Winforms client

Time:12-30

I have a SignalR hub where messages are reaching from client but callback not seems to work.

Server code:

public class ChatHub : Hub<IChatClient>
{
    private readonly ILogger<ChatHub> _logger;

    public ChatHub(ILogger<ChatHub> logger)
    {
        _logger = logger;
    }

    public async Task SendMessage(ChatMessage message)
    {
        try
        {
            if (message != null && message.From > 0 && message.To > 0)
            {
               ....
            }

            await Clients.All.ReceiveMessage(message);
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, $"Error in SendMessage  {ex.Message}");
        }
    }
}

Client code for configuring the SignalR:

 private void connectChat()
    {
        _signalRConnection = new HubConnectionBuilder()
           .WithUrl(Properties.Settings.Default.APIPath   "/hubs/chat").WithAutomaticReconnect()
           .Build();

         try
        {

            //Connect to the server
            _signalRConnection.StartAsync().ContinueWith(task =>
            {
                if (task.IsFaulted)
                {
                    this.Invoke(new Action(() => txtMessages.AppendText("There was an error opening the connection: "   task.Exception.GetBaseException().Message)));
                }
                else
                {
                    this.Invoke(new Action(() => txtMessages.AppendText("Connected")));
                }
            });

            _signalRConnection.On<string, ChatMessage>("ReceiveMessage", (name, message) =>
            {
                if (txtMessages.InvokeRequired)
                {
                    txtMessages.Invoke(new Action(() => txtMessages.AppendText($"{name} : {message?.MessageText}"   Environment.NewLine)));
                }
                else
                {
                    txtMessages.AppendText($"{name} : {message?.MessageText}"   Environment.NewLine);
                }
            });
        }
        catch (Exception)
        {
            throw;
        }
    }   

Client code for sending message

ChatMessage message = new ChatMessage();

message.MessageText = txtChatMessage.Text;
message.From = UserId.Value;
message.To = toStation;
message.MessageTime = DateTime.Now;

_signalRConnection.SendAsync("SendMessage", message).Wait();

CodePudding user response:

There are a few important details that you need to pay attention to them, for example, make sure:

  • You are using the right URL
  • The server app is running, before you try to connect
  • Start the connection, and wait until the app connects to the hub
  • You have correct configurations
  • You are using correct callback names for send and receive.

There are two walkthrough docs & learn article which can help you to create a SignalR server and client:

Windows Forms SignarR client for a ASP.NET Core SignarlR server

Using above mentioned links, here is a very quick step by step example on how to send and receive SignalR messages in a Windows Forms application. In this example, the chat server app is an ASP.NET Core Web application, and the client app is a Windows Forms Application.

Clone or download example

Step by step guide

1 - Create the host application

  1. Create an ASP.NET Core Web application, with name SignalRChat. (Enable HTTPS, and use .NET 6)

  2. Create a folder in the project, with name Hubs. And add a new file to it, ChatHub.cs, with the following content:

    using Microsoft.AspNetCore.SignalR;
    
    namespace SignalRChat.Hubs
    {
        public class ChatHub : Hub
        {
            public async Task SendMessage(string user, string message)
            {
                await Clients.All.SendAsync("ReceiveMessage", user, message);
            }
        }
    }
    
  3. Add SignalR configuration to the Program.cs. Here's the file content after the config added:

    using SignalRChat.Hubs;
    
    var builder = WebApplication.CreateBuilder(args);
    
    // Add services to the container.
    builder.Services.AddRazorPages();
    builder.Services.AddSignalR();
    
    var app = builder.Build();
    
    // Configure the HTTP request pipeline.
    if (!app.Environment.IsDevelopment())
    {
        app.UseExceptionHandler("/Error");
        app.UseHsts();
    }
    
    app.UseHttpsRedirection();
    app.UseStaticFiles();
    
    app.UseRouting();
    
    app.UseAuthorization();
    
    app.MapRazorPages();
    app.MapHub<ChatHub>("/chatHub");
    
    app.Run();
    

2 - Create the client application

  1. Create a new WinForms application (.NET 6), with name SignalRChatClient.

  2. Drop a button, with name connectButton

  3. Drop a button, with name sendButton

  4. Drop a textBox, with name userTextBox

  5. Drop a textBox, with name messageTextBox

  6. Drop a listBox, with name messagesList

  7. Double click on connectButton to add the empty event handler to the form. We will add the body later.

  8. Double click on sendButton to add the empty event handler to the form. We will add the body later.

  9. Replace the Form1.cs content with the following content: using Microsoft.AspNetCore.SignalR.Client;

    namespace SignalRChatClient
    {
        public partial class Form1 : Form
        {
            HubConnection connection;
            public Form1()
            {
                InitializeComponent();
                connection = new HubConnectionBuilder()
                   .WithUrl("https://localhost:7142/ChatHub")
                   .WithAutomaticReconnect()
                   .Build();
            }
    
            private async void connectButton_Click(object sender, EventArgs e)
            {
                connection.On<string, string>("ReceiveMessage", (user, message) =>
                {
                    this.Invoke((Delegate)(() =>
                    {
                        var newMessage = $"{user}: {message}";
                        messagesList.Items.Add(newMessage);
                    }));
                });
    
                try
                {
                    await connection.StartAsync();
                    messagesList.Items.Add("Connection started");
                    connectButton.Enabled = false;
                    sendButton.Enabled = true;
                }
                catch (Exception ex)
                {
                    messagesList.Items.Add(ex.Message);
                }
            }
    
            private async void sendButton_Click(object sender, EventArgs e)
            {
                try
                {
                    await connection.InvokeAsync("SendMessage",
                        userTextBox.Text, messageTextBox.Text);
                }
                catch (Exception ex)
                {
                    messagesList.Items.Add(ex.Message);
                }
            }
        }
    }
    
  10. Important!: Make sure you modify the URL to the value for your environment. To do so, you can run the web app and see the URL in the browser, or you can open launchSettings.json file and see the URL based on the profile. I'm debugging in VS, so I used the URL https://localhost:7142 from this node:

    "profiles": {
     "SignalRExample": {
       "commandName": "Project",
       "dotnetRunMessages": true,
       "launchBrowser": true,
       "applicationUrl": "https://localhost:7142;http://localhost:5142",
       "environmentVariables": {
         "ASPNETCORE_ENVIRONMENT": "Development"
       }
     },
    

3 - Set multiple Strartup and run

  1. Right click on the solution and choose Properties
  2. In the start up projects, choose Multiple Startup Projects and for both SignalRChat and SignalRChatClient choose Start, and save changes.

Now you can press F5 and run the project. Wait until the web browser opens and navigates to the web app. The Windows Form will also open and Form1 will be shown.

Press on Connect button, then after seeing the "Connection started" message in the list, type a username and a message in the text boxes and press Send, and you will receive the message in the list.

There you go!

CodePudding user response:

I think it is because your client method ReceiveMessage has one parameter:

await Clients.All.ReceiveMessage(message);

While binding event handler you are binding two parameters:

_signalRConnection.On<string, ChatMessage>("ReceiveMessage", (name, message) =>

Correct this to bind right number of parameters.

_signalRConnection.On<ChatMessage>("ReceiveMessage", (message) =>
  • Related