Alexander
Alexander

Reputation: 91

Using the new signalR for DotNet core to send messages from console App to web page

I am using this example from https://blogs.msdn.microsoft.com/webdev/2017/09/14/announcing-signalr-for-asp-net-core-2-0/ to create a console app that can send messages from a simple console app to a web page.

Below is the simple example for console application which reads the user input and prints that input on the screen, I want to send the same user input also to the web page.

static void Main(string[] args)
        {
            while (true)
            {
                Console.WriteLine("Enter input:");
                string line = Console.ReadLine();
                if (line == "exit")
                {
                    break;
                }
                sendSignalToClient(line);
                Console.Write("Message Sent To Client: " + line);
            }
        }

        private static void sendSignalToClient(string line)
        {
            //Send a message from this app to web client using signalR
        }

I have just started learning about this. Any material or suggestions related to this is appreciated. -Thanks

Edit: I am using a sample signalR chat application.

public class Program
    {
        public static void Main(string[] args)
        {
            BuildWebHost(args).Run();
        }

        public static IWebHost BuildWebHost(string[] args) =>
            WebHost.CreateDefaultBuilder(args)
                .UseStartup<Startup>()
                .Build();
    }

public class ChatHub : Hub
    {
        public void Send(string name, string message)
        {
            // Call the broadcastMessage method to update clients.
            Clients.All.InvokeAsync("broadcastMessage", name, message);
        }
    }

public class Startup
    {
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddSignalR();
        }

        public void Configure(IApplicationBuilder app, IHostingEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }
            app.UseFileServer();

            app.UseSignalR(routes =>
            {
                routes.MapHub<ChatHub>("chat");
            });
        }

Below is the code for the console application that is sending messages to web page

class Program : Hub
{
    static void Main(string[] args)
    {
        Task.Run(Run).Wait();
    }

    static async Task Run()
    {
        var connection = new HubConnectionBuilder()
            .WithUrl("http://localhost:59768/chat")
            .WithConsoleLogger()
            .WithMessagePackProtocol()
            .WithTransport(TransportType.WebSockets)
            .Build();

        await connection.StartAsync();

        Console.WriteLine("Starting connection. Press Ctrl-C to close.");
        var cts = new CancellationTokenSource();
        Console.CancelKeyPress += (sender, a) =>
        {
            a.Cancel = true;
            cts.Cancel();
        };

        connection.Closed += e =>
        {
            Console.WriteLine("Connection closed with error: {0}", e);

            cts.Cancel();
            return Task.CompletedTask;
        };

        connection.On("broadcastMessage", async () =>
        {


        });

        while (true)
        {
            Thread.Sleep(2000);

            await connection.SendAsync("send", "alex", "hello");

        }
    }

All the code is working but on the console application i am receiving this exception:

 Microsoft.AspNetCore.Sockets.Client.HttpConnection[19]
      09/17/2017 13:47:17: Connection Id 40da6d4b-9c47-4831-802f-628bbb172e10: An exception was thrown from the 'Received' event handler.
System.FormatException: Target method expects 0 arguments(s) but invocation has 2 argument(s).
   at Microsoft.AspNetCore.SignalR.Internal.Protocol.MessagePackHubProtocol.CreateInvocationMessage(Unpacker unpacker, IInvocationBinder binder)
   at Microsoft.AspNetCore.SignalR.Internal.Protocol.MessagePackHubProtocol.TryParseMessages(ReadOnlyBuffer`1 input, IInvocationBinder binder, IList`1& messages)
   at Microsoft.AspNetCore.SignalR.Internal.HubProtocolReaderWriter.ReadMessages(Byte[] input, IInvocationBinder binder, IList`1& messages)
   at Microsoft.AspNetCore.SignalR.Client.HubConnection.<OnDataReceivedAsync>d__31.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at Microsoft.AspNetCore.Sockets.Client.HttpConnection.<>c__DisplayClass49_0.<<ReceiveAsync>b__0>d.MoveNext()

Upvotes: 5

Views: 7616

Answers (2)

Juan G Carmona
Juan G Carmona

Reputation: 2208

Take a look at this tutorial because although it is bit old it would give you good advices:

https://learn.microsoft.com/en-us/aspnet/signalr/overview/getting-started/tutorial-getting-started-with-signalr

On the one hand you web page needs to connect to a SignalR Hub and on the other your console should connect to a service, probably in you web project, to send the message to the hub and from there to all the registered clients. The key is that the hub executes JavaScript functions in client side but it has to know the clients, due to a registration, and that hub instance had to be called to execute is methods. What makes me sense is to inject the hub in an API controller and, using httpclient, post the inputs to your controller.

Another good tutorial but this one is very recent:

https://spontifixus.github.io/ASPNET-Core-SignalR-with-Aurelia-and-Webpack/

I hope it helps.

Juan

EDIT:

I've just found an answer (may 2017) to the same question here:

SignalR Console app example

In server side:

 [HubName("MyHub")]
        public class MyHub : Hub
        {
            public void Send(string name, string message)
            {
                Clients.All.addMessage(name, message);
            }
        }

And in client side:

 var myHub = connection.CreateHubProxy("MyHub");
...
// To write received messages:
 myHub.On<string, string>("addMessage", (s1, s2) => {
                        Console.WriteLine(s1 + ": " + s2);
                    });
...
// To send messages:
 myHub.Invoke<string>("Send", name, message).ContinueWith(task1 => {
                            if (task1.IsFaulted)
                            {
                                Console.WriteLine("There was an error calling send: {0}", task1.Exception.GetBaseException());
                            }
                            else
                            {
                                Console.WriteLine(task1.Result);
                            }
                        });

This might work for you too Alexander.

I hope it helps.

Juan

Upvotes: 3

davidfowl
davidfowl

Reputation: 38885

Your event handler should take a string argument, it should look like this:

connection.On<string>("broadcastMessage", data =>
{

});

Upvotes: 5

Related Questions