前陣子把玩了一下SignalR,起初以為只是個real-time的web通訊組件。研究了幾天后發現,這玩意簡直屌炸天,它完全就是個.net的雙向異步通訊框架,用它能做很多不可思議的東西。它基於Owin,可以脫離繁重的System.Web,隨意寄宿在IIS,WindowsService,或者一個控制台程序,這樣它即能用於b/s的Web應用,也能用在客戶端程序或者服務之間的通訊上。對它的介紹網上早已鋪天蓋地,這而就不再啰嗦了,先來個小例子,一個聊天室程序。
服務端
新建一個叫SignalRDemo的工程,注意一定要選擇.net Framework4.5及以上。
為了讓服務端可以自寄宿,安裝signalr self host組件。
public class ChatHub : Hub { public void Send(string name, string message) { Console.WriteLine("ConnectionId:{0}, InvokeMethod:{1}", Context.ConnectionId, "Send"); Clients.AllExcept(Context.ConnectionId).broadcast(name, message); } }
新建一個ChatHub,創建一個行為叫Send,里面包含了一條控制台調用記錄以及讓所有除了發起者外的鏈接Hub的客戶端執行客戶端方法broadcast。
[assembly: OwinStartup(typeof(Host.Startup))] namespace Host { public class Startup { public void Configuration(IAppBuilder app) { app.MapSignalR(); } } }
創建一個啟動類,將所有的Hub映射。
class Program { static void Main(string[] args) { var url = "localhost:10086"; WebApp.Start<Startup>(url); Console.WriteLine("Server started,url is {0}", url); Console.ReadLine(); } }
在Main中寫上url和端口,直接用WebApp啟動。
控制台啟動后的輸出。
用瀏覽器訪問
好了,到這兒服務端代碼就全部完成了。接下來創建客戶端來調用。客戶端暫時不采用website,同樣用控制台程序來承載。
客戶端
創建一個Client的控制台工程,添加SignalR的Client包。
var url = "http://localhost:10086/"; var connection = new HubConnection(url); var chatHub = connection.CreateHubProxy("ChatHub"); connection.Start().ContinueWith(t => { if (t.IsFaulted) { Console.WriteLine("Connection fault."); } });
在客戶端的Main中創建一個HubConnection,創建ChatHub的代理,通過connection.Start啟動連接。
var broadcastHandler = chatHub.On<string, string>("broadcast", (name, message) => { Console.WriteLine("[{0}]{1}: {2}", DateTime.Now.ToString("HH:mm:ss"), name, message); });
定義客戶端方法,之前在服務端用Clients.All.broadcast的就是在這邊定義的方法。
Console.WriteLine("Please input your name:"); var _name = Console.ReadLine(); Console.WriteLine("Start chat!"); while (true) { var _message = Console.ReadLine(); chatHub.Invoke("Send", _name, _message).ContinueWith(t => { if (t.IsFaulted) { Console.WriteLine("Connection error!"); } }); }
最后,寫上一個簡單的聊天邏輯。當輸入名字后,在while的循環內,每輸入一行文本,hub就調用服務端的Send方法。同時服務端在執行Send的過程后又會回掉客戶端方法。這種通訊方式在以前的C#代碼中是很不可思議的,因為同樣的客戶端方法還可以寫在js里!
執行效果
執行效果如圖。
好了,一個基於SignalR的簡單的控制台聊天程序就完成了,強大的SignalR讓開發者不需要關心Socket的一堆煩人的問題。
問題
上面的那個聊天程序看似很方便很強大,但似乎哪兒有一些奇怪?
比如說,服務端調用客戶端的方法用的是dynamic的,客戶端調用服務端的方法傳入的都是string類型的,這樣首先就不具備擴展性和進行一些規則約束。
- 能不能讓客戶端聲明一個強類型的方法列表呢?這樣首先不容易寫錯。
- 同樣的,能不能讓服務端聲明一個強類型的方法列表給客戶端調用呢?
下一篇將對上面的2個問題進行思考,並給出解決方案。