SignalR控制台应用示例

110
有没有一个使用SignalR向.NET Hub发送消息的控制台或Winform应用程序的小例子?我已经尝试了.NET示例并查看了Wiki,但我不明白Hub(.NET)与客户端(控制台应用程序)之间的关系(找不到此类示例)。这个应用程序只需要连接到Hub的地址和名称吗?
如果有人能提供一个小代码片段,显示应用程序连接到一个Hub并发送“Hello World”或其他.NET Hub接收到的内容。
PS:我有一个标准的Hub聊天示例,它运行良好,但是如果我尝试将其分配给Cs中的Hub名称,它会停止工作,即[HubName("test")],你知道原因吗?
谢谢。
当前控制台应用程序代码。
static void Main(string[] args)
{
    //Set connection
    var connection = new HubConnection("http://localhost:41627/");
    //Make proxy to hub based on hub name on server
    var myHub = connection.CreateProxy("chat");
    //Start connection
    connection.Start().ContinueWith(task =>
    {
        if (task.IsFaulted)
        {
            Console.WriteLine("There was an error opening the connection:{0}", task.Exception.GetBaseException());
        }
        else
        {
            Console.WriteLine("Connected");
        }
    }).Wait();

    //connection.StateChanged += connection_StateChanged;

    myHub.Invoke("Send", "HELLO World ").ContinueWith(task => {
        if(task.IsFaulted)
        {
            Console.WriteLine("There was an error calling send: {0}",task.Exception.GetBaseException());
        }
        else
        {
            Console.WriteLine("Send Complete.");
        }
    });
 }

中央服务器(另一个项目工作区)

public class Chat : Hub
{
    public void Send(string message)
    {
        // Call the addMessage method on all clients
        Clients.addMessage(message);
    }
}

这个的信息维基是 http://www.asp.net/signalr/overview/signalr-20/hubs-api/hubs-api-guide-net-client


好的,实际上这个方法确实有效,我只是以为会得到相同的结果,所以在结尾添加了一些停止点和 Console.ReadLine();。哇! - user685590
5个回答

130

首先,您应该通过NuGet在服务器应用程序上安装SignalR.Host.Self,并在客户端应用程序上安装SignalR.Client:

PM> Install-Package SignalR.Hosting.Self -Version 0.5.2

PM> Install-Package Microsoft.AspNet.SignalR.Client

然后将以下代码添加到您的项目中;)

(以管理员身份运行项目)

服务器控制台应用程序:

using System;
using SignalR.Hubs;

namespace SignalR.Hosting.Self.Samples {
    class Program {
        static void Main(string[] args) {
            string url = "http://127.0.0.1:8088/";
            var server = new Server(url);

            // Map the default hub url (/signalr)
            server.MapHubs();

            // Start the server
            server.Start();

            Console.WriteLine("Server running on {0}", url);

            // Keep going until somebody hits 'x'
            while (true) {
                ConsoleKeyInfo ki = Console.ReadKey(true);
                if (ki.Key == ConsoleKey.X) {
                    break;
                }
            }
        }

        [HubName("CustomHub")]
        public class MyHub : Hub {
            public string Send(string message) {
                return message;
            }

            public void DoSomething(string param) {
                Clients.addMessage(param);
            }
        }
    }
}

客户端控制台应用程序:

using System;
using SignalR.Client.Hubs;

namespace SignalRConsoleApp {
    internal class Program {
        private static void Main(string[] args) {
            //Set connection
            var connection = new HubConnection("http://127.0.0.1:8088/");
            //Make proxy to hub based on hub name on server
            var myHub = connection.CreateHubProxy("CustomHub");
            //Start connection

            connection.Start().ContinueWith(task => {
                if (task.IsFaulted) {
                    Console.WriteLine("There was an error opening the connection:{0}",
                                      task.Exception.GetBaseException());
                } else {
                    Console.WriteLine("Connected");
                }

            }).Wait();

            myHub.Invoke<string>("Send", "HELLO World ").ContinueWith(task => {
                if (task.IsFaulted) {
                    Console.WriteLine("There was an error calling send: {0}",
                                      task.Exception.GetBaseException());
                } else {
                    Console.WriteLine(task.Result);
                }
            });

            myHub.On<string>("addMessage", param => {
                Console.WriteLine(param);
            });

            myHub.Invoke<string>("DoSomething", "I'm doing something!!!").Wait();


            Console.Read();
            connection.Stop();
        }
    }
}

你可以在Windows应用程序中使用上述代码,但真的有必要吗?!我不确定你的意思,你还可以用其他方式在Windows中通知。 - Mehrdad Bahrainy
1
客户端适用于服务器0.5.2至1.0.0-alpha2版本。例如,安装Microsoft.AspNet.SignalR.Client-版本1.0.0-alpha2:https://www.nuget.org/packages/Microsoft.AspNet.SignalR.Client/1.0.0-alpha2 (代码和SignalR版本应与使用VS2010 SP1的.net 4.0兼容)。一直在尝试找出为什么无法使其工作,最终尝试了早期版本的SignalR。 - Nick Giles
很好,真的很有帮助。 - Dika Arta Karunia
5
请注意,在调用 connection.Start() 方法之前,您需要添加事件侦听器(即 .On<T>() 方法调用)。 - user1229323
值得提供此链接:https://learn.microsoft.com/zh-cn/aspnet/signalr/overview/guide-to-the-api/hubs-api-guide-net-client - Mohammed Noureldin

31

SignalR 2.2.1 示例(2017年5月)

服务器端

安装 Microsoft.AspNet.SignalR.SelfHost 包 - 版本 2.2.1

[assembly: OwinStartup(typeof(Program.Startup))]
namespace ConsoleApplication116_SignalRServer
{
    class Program
    {
        static IDisposable SignalR;

        static void Main(string[] args)
        {
            string url = "http://127.0.0.1:8088";
            SignalR = WebApp.Start(url);

            Console.ReadKey();
        }

        public class Startup
        {
            public void Configuration(IAppBuilder app)
            {
                app.UseCors(CorsOptions.AllowAll);

                /*  CAMEL CASE & JSON DATE FORMATTING
                 use SignalRContractResolver from
                https://dev59.com/Tl0a5IYBdhLWcg3wuKw7

                var settings = new JsonSerializerSettings()
                {
                    DateFormatHandling = DateFormatHandling.IsoDateFormat,
                    DateTimeZoneHandling = DateTimeZoneHandling.Utc
                };

                settings.ContractResolver = new SignalRContractResolver();
                var serializer = JsonSerializer.Create(settings);
                  
               GlobalHost.DependencyResolver.Register(typeof(JsonSerializer),  () => serializer);                
            
                 */

                app.MapSignalR();
            }
        }

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

客户端

(与Mehrdad Bahrainy的回复几乎相同)

Install-Package Microsoft.AspNet.SignalR.Client -Version 2.2.1

namespace ConsoleApplication116_SignalRClient
{
    class Program
    {
        private static void Main(string[] args)
        {
            var connection = new HubConnection("http://127.0.0.1:8088/");
            var myHub = connection.CreateHubProxy("MyHub");

            Console.WriteLine("Enter your name");    
            string name = Console.ReadLine();

            connection.Start().ContinueWith(task => {
                if (task.IsFaulted)
                {
                    Console.WriteLine("There was an error opening the connection:{0}", task.Exception.GetBaseException());
                }
                else
                {
                    Console.WriteLine("Connected");

                    myHub.On<string, string>("addMessage", (s1, s2) => {
                        Console.WriteLine(s1 + ": " + s2);
                    });

                    while (true)
                    {
                        Console.WriteLine("Please Enter Message");
                        string message = Console.ReadLine();

                        if (string.IsNullOrEmpty(message))
                        {
                            break;
                        }

                        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);
                            }
                        });
                    }
                }

            }).Wait();

            Console.Read();
            connection.Stop();
        }
    }
}

4
无法运行...在WebApp.Start()处引发了空引用异常。 - Fᴀʀʜᴀɴ Aɴᴀᴍ
也许你知道如何在这个自托管的SignalR服务器中全局设置JSON序列化设置(例如camelCase)? - Xaris Fytrakis
2
@XarisFytrakis 非常简单,我已经更新了答案,你需要从这里获取合同解析器:https://dev59.com/Tl0a5IYBdhLWcg3wuKw7,以及DateFormatHandling = DateFormatHandling.IsoDateFormat,如果你从js中使用它。 - Alexander Selishchev
@ADOConnection 感谢您的快速回复。现在的问题是从 .net 客户端调用方法时出现的问题。例如,如果我在 Hub 类中调用此方法:HubContext.Clients.All.UpdateMetric(new { Data = "xxx", Something = "yyy" }, username); 我会得到正确序列化设置(驼峰式大小写)的 json 响应。但是,如果我像这样使用来自客户端(asp.net 客户端)的传递数据进行调用:public void UpdateMetric(object metrics, string username) { HubContext.Clients.All.UpdateMetric(metrics, username); 客户端上的结果不是驼峰式大小写。 - Xaris Fytrakis

14
继续@dyslexicanaboko的回答,为了在dotnet core上构建,这里是一个客户端控制台应用程序:
创建一个辅助类:
using System;
using Microsoft.AspNetCore.SignalR.Client;

namespace com.stackoverflow.SignalRClientConsoleApp
{
    public class SignalRConnection
    {
        public async Task Start()
        {
            var url = "http://signalr-server-url/hubname";

            var connection = new HubConnectionBuilder()
                .WithUrl(url)
                .WithAutomaticReconnect()
                .Build();

            // receive a message from the hub
            connection.On<string, string>("ReceiveMessage", OnReceiveMessage);

            await connection.StartAsync();

            // send a message to the hub
            await connection.InvokeAsync("SendMessage", "ConsoleApp", "Message from the console app");
        }

        private void OnReceiveMessage(string user, string message)
        {
            Console.WriteLine($"{user}: {message}");
        }

    }
}

然后在您的控制台应用程序的入口点中实现:
using System;

namespace com.stackoverflow.SignalRClientConsoleApp
{
    class Program
    {
        static void Main(string[] args)
        {
            var signalRConnection = new SignalRConnection();
            signalRConnection.Start();

            Console.Read();
        }
    }
}

5
你的回答对我非常有帮助,但是在现代平台上使用类似Java命名空间的写法有点可笑。 - Federico Berasategui
2
@FedericoBerasategui 哈哈,我一直认为Java的命名空间约定非常有结构性,而且想知道为什么微软没有采用相同的方式。经过了解,我才意识到这只是一个老旧的事情。感谢您的提醒。 - tno2007

8

6

这是针对.NET Core 2.1的 - 经过多次尝试和错误,我最终使其完美运行:

var url = "Hub URL goes here";

var connection = new HubConnectionBuilder()
    .WithUrl($"{url}")
    .WithAutomaticReconnect() //I don't think this is totally required, but can't hurt either
    .Build();

//Start the connection
var t = connection.StartAsync();

//Wait for the connection to complete
t.Wait();

//Make your call - but in this case don't wait for a response 
//if your goal is to set it and forget it
await connection.InvokeAsync("SendMessage", "User-Server", "Message from the server");

这段代码来自一个典型的SignalR穷人版聊天客户端。我和许多其他人遇到的问题是在尝试向中心发送消息之前建立连接。这是至关重要的,因此必须等待异步任务完成 - 这意味着我们通过等待任务完成使其成为同步。


你实际上可以将connection.StartAsync和Wait()串联起来,写成 connection.StartAsync.Wait()。 - DiTap

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接