在Windows Phone (WP8) 中使用SignalR
ASP.NET SignalR【幾乎】讓我想丟掉Push Notification,你就知道它把訊息傳遞這件事情弄得有多簡單方便了。在這一篇我說明一下如何在WP8中使用ASP.NET SignalR,同時也稍微解釋一下這兩天寫的Code。
請回憶一下我們昨天的情境:
我們在伺服器端透過ASP.NET以SignalR寫了一組服務,主要是用來做聊天室(基本上是範例啦)的功能,包含了接收用戶端傳來的訊息(姓名、聊天文字),以及把訊息主動推送給用戶端(姓名、聊天文字),這樣的功能。
而用戶端就很單純的呼叫或傾聽這個服務。呼叫Send方法可以把用戶端使用者想要說的訊息傳給伺服器端,而伺服器端收到,則執行broadcastMessage這個動態方法,把訊息推送給所有傾聽的用戶端。
透過ASP.NET SignalR要寫這個服務端的機制,很簡單。
首先,建立一個Empty WebForm專案(當然你用MVC也行,之所以用WebForm,原因在這裡),接著透過NuGet引用ASP.NET SignalR:
然後在專案中Add New Item,請找到Hub Class(VS2012 Update 4或VS2013):
建立出來的Class如下:
該類別繼承自Hub,這個Hub就是SignalR服務的Bass Class,你可以在其中建立自己的Method,如上圖中的Hello。
我們修改此類別,建立一個聊天室中,接收用戶端傳來訊息的Method,名稱為Send, 其程式碼如下:
注意上面的Method Send,是用來讓Client端(WPF or WP8)呼叫的,用來把用戶端輸入的聊天訊息傳送到伺服器端,所以有兩個參數 name 和 message。而broadcastMessage也是我們自己定義的Method,用來把訊息傳遞到用戶端。
不過,很有趣的是,這邊用到了Dynamic Method的概念,這個部分我們過去不常談論,但這機制讓我們可以在程式碼中動態的建立類別的方法和屬性。例如上面這個broadcastMessage,本來Clients.All.底下根本沒這個Method,這是我們自己在Visual Studio寫程式時候直接加進去的,參數也是我們當下自己決定的。也因此,這部分Visual Studio是無法幫我們檢查是否有拼字或語法錯誤,你得要自己留意。
透過Clients.All.類別,可以讓我們把特定的資訊推送給用戶端(只要用戶端有設定好connection並傾聽),所以你看到上面的程式碼,我們在收到某一個用戶端透過呼叫Send方法所傳來的訊息之後,就透過Clients.All.broadcastMessage(用戶名 , 聊天訊息)把該訊息傳給所有用戶端。
這樣,只要任何一個用戶端(WPF or WP8 or Windows Form or ...)把聊天訊息傳到到伺服器端,透過伺服器端的broadcastMessage方法,所有傾聽的用戶端就會收到聊天訊息囉:
伺服器端程式碼的撰寫就是那麼簡單,不過別忘了ASP.NET SignalR必須註冊在Web.Config中,所以你必須撰寫一個Configuration方法:
然後得在Web.Config中註冊:
這樣該Hub才會運行起來。
以上是伺服器端的部分,那用戶端呢? 我們來看看WP8的用戶端App。坦白說,用戶端可就真的很簡單了,如同前面說的,簡單到我【幾乎】(但其實並沒有)想把Push Notification給丟了。
用戶端(不管是WP8 or WPF or Windows Form or ...),只需要透過NuGet引用SignalR .NET Client即可:
接著,就可以直接使用伺服器端寫好的服務囉。若想要傳送訊息到伺服器端,程式碼大致如下:
基本上就是呼叫我們伺服器端寫的Send方法。而其中的Proxy哪來的? 請看底下程式碼:
我們在Loaded事件中,透過HubConnection來建立伺服器端的連線,跟以前使用Web/WCF Services差不多,請留意CreateHubProxy中的MyHub1,就是先前我們在伺服器端建立的Hub Class Name,在Proxy.On這邊,做了一個註冊傾聽的動作,一旦服務器端有呼叫broadcastMessage把訊息往用戶端傳,我們的WP8 App就會收到,並且執行25,26行中的程式碼。(注意這邊用到了匿名方法、以及非UI執行續的Dispatcher,因為該行為是非同步的)
另外,我特別用asp.net寫一個webform的網頁,示範由伺服器端主動送訊息給用戶端:
其程式碼如下:
這說明了即便不是從用戶端觸發,伺服器端也可以輕鬆的主動傳送訊息給正在傾聽的用戶端。
就這樣,程式寫完了,範例在這裡。
========================================================================
後記:
SignalR 用了OWIN這個 .net 的輕量級小組件,拋棄了龐大的.NET Framework,這其實是很有趣的事情,他再一次的說明了資訊界~天下合久必分分久必合~的道理,以前大家想要一組完整的framework(Java or .NET),覺得寫程式拼拼裝裝的很辛苦。現在又覺得framework太大了,而且有相依性的問題,所以又想要自由一點,自己兜出想要的解決方案。
為何會有這樣的改變呢? 過去不可行的,為何現在可行了??? 我想開發工具越來越便利是其中之一的原因,以前(1999年之前)開發人員在沒有framework的情況下,想要蒐集需要的套件很累,現在有Google、有stackoverflow、有NuGet...事情變簡單了,大家就想要提高自由度了,相形之下,一整套Framework似乎就太龐大了。
前端開發技術也是,以前大家想要total solutions,現在JavaScript Framework喜歡自己兜,服務端開發技術也是,以前想要制定一整套的服務描述和查找方法,所以有Web Services和WSDL,現在大家把這些丟了,然後重來一次,就有了RESTful、Web API、JSON、和SignalR這類的技術整合和應用...
天下合久必分、分久必合,所以我開始收斂地不太敢再說趨勢和所謂的主流,因為....你只要Coding的生涯夠長,會發現所有的開發技術,終將都會改變、只要你能活得夠久,終將目睹某個開發技術的興起與消逝。
請回憶一下我們昨天的情境:
我們在伺服器端透過ASP.NET以SignalR寫了一組服務,主要是用來做聊天室(基本上是範例啦)的功能,包含了接收用戶端傳來的訊息(姓名、聊天文字),以及把訊息主動推送給用戶端(姓名、聊天文字),這樣的功能。
而用戶端就很單純的呼叫或傾聽這個服務。呼叫Send方法可以把用戶端使用者想要說的訊息傳給伺服器端,而伺服器端收到,則執行broadcastMessage這個動態方法,把訊息推送給所有傾聽的用戶端。
透過ASP.NET SignalR要寫這個服務端的機制,很簡單。
首先,建立一個Empty WebForm專案(當然你用MVC也行,之所以用WebForm,原因在這裡),接著透過NuGet引用ASP.NET SignalR:
然後在專案中Add New Item,請找到Hub Class(VS2012 Update 4或VS2013):
建立出來的Class如下:
public class MyHub1 : Hub { public void Hello() { Clients.All.hello(); } }
該類別繼承自Hub,這個Hub就是SignalR服務的Bass Class,你可以在其中建立自己的Method,如上圖中的Hello。
我們修改此類別,建立一個聊天室中,接收用戶端傳來訊息的Method,名稱為Send, 其程式碼如下:
public class MyHub1 : Hub //SignalR主要部分 { public void Send(string name, string message) //接收傳送來的訊息 { //傳送訊息到用戶端 Clients.All.broadcastMessage(name, message); //廣播訊息 (這邊用到了動態方法) } }
注意上面的Method Send,是用來讓Client端(WPF or WP8)呼叫的,用來把用戶端輸入的聊天訊息傳送到伺服器端,所以有兩個參數 name 和 message。而broadcastMessage也是我們自己定義的Method,用來把訊息傳遞到用戶端。
不過,很有趣的是,這邊用到了Dynamic Method的概念,這個部分我們過去不常談論,但這機制讓我們可以在程式碼中動態的建立類別的方法和屬性。例如上面這個broadcastMessage,本來Clients.All.底下根本沒這個Method,這是我們自己在Visual Studio寫程式時候直接加進去的,參數也是我們當下自己決定的。也因此,這部分Visual Studio是無法幫我們檢查是否有拼字或語法錯誤,你得要自己留意。
透過Clients.All.類別,可以讓我們把特定的資訊推送給用戶端(只要用戶端有設定好connection並傾聽),所以你看到上面的程式碼,我們在收到某一個用戶端透過呼叫Send方法所傳來的訊息之後,就透過Clients.All.broadcastMessage(用戶名 , 聊天訊息)把該訊息傳給所有用戶端。
這樣,只要任何一個用戶端(WPF or WP8 or Windows Form or ...)把聊天訊息傳到到伺服器端,透過伺服器端的broadcastMessage方法,所有傾聽的用戶端就會收到聊天訊息囉:
伺服器端程式碼的撰寫就是那麼簡單,不過別忘了ASP.NET SignalR必須註冊在Web.Config中,所以你必須撰寫一個Configuration方法:
[assembly: OwinStartup(typeof(WebApplication5.Startup1))] namespace WebApplication5 { public class Startup1 //必須在web.config中註冊 { public void Configuration(IAppBuilder app) { // For more information on how to configure your application, visit http://go.microsoft.com/fwlink/?LinkID=316888 app.MapSignalR(); } } }
然後得在Web.Config中註冊:
這樣該Hub才會運行起來。
以上是伺服器端的部分,那用戶端呢? 我們來看看WP8的用戶端App。坦白說,用戶端可就真的很簡單了,如同前面說的,簡單到我【幾乎】(但其實並沒有)想把Push Notification給丟了。
用戶端(不管是WP8 or WPF or Windows Form or ...),只需要透過NuGet引用SignalR .NET Client即可:
接著,就可以直接使用伺服器端寫好的服務囉。若想要傳送訊息到伺服器端,程式碼大致如下:
private void ApplicationBarIconButton_Click(object sender, EventArgs e) { //從Client端送訊息 proxy.Invoke("Send", TxbName.Text, TxbMessage.Text); }
基本上就是呼叫我們伺服器端寫的Send方法。而其中的Proxy哪來的? 請看底下程式碼:
HubConnection connection; IHubProxy proxy; // Constructor public MainPage() { InitializeComponent(); Loaded += MainPage_Loaded; // Sample code to localize the ApplicationBar //BuildLocalizedApplicationBar(); } void MainPage_Loaded(object sender, RoutedEventArgs e) { //建立connection, proxy connection = new HubConnection("http://signalrtestsite.azurewebsites.net"); //測試位置,請自行建立 proxy = connection.CreateHubProxy("MyHub1"); connection.Start(); //listen broadcastMessage proxy.On<string , string>( "broadcastMessage", (name, msg) => { //非同步(在非UI執行序中)顯示訊息 this.Dispatcher.BeginInvoke( () => { lblShow.Text = "" + name + ":" + msg + "\n" + lblShow.Text; }); } ); }
我們在Loaded事件中,透過HubConnection來建立伺服器端的連線,跟以前使用Web/WCF Services差不多,請留意CreateHubProxy中的MyHub1,就是先前我們在伺服器端建立的Hub Class Name,在Proxy.On這邊,做了一個註冊傾聽的動作,一旦服務器端有呼叫broadcastMessage把訊息往用戶端傳,我們的WP8 App就會收到,並且執行25,26行中的程式碼。(注意這邊用到了匿名方法、以及非UI執行續的Dispatcher,因為該行為是非同步的)
另外,我特別用asp.net寫一個webform的網頁,示範由伺服器端主動送訊息給用戶端:
其程式碼如下:
protected void Button1_Click(object sender, EventArgs e) { //透過GlobalHost使用hub instanc var context = GlobalHost.ConnectionManager.GetHubContext(); //由伺服器端主動發訊息 context.Clients.All.broadcastMessage("admin", TextBox1.Text + " " + System.DateTime.Now.ToString()); }
這說明了即便不是從用戶端觸發,伺服器端也可以輕鬆的主動傳送訊息給正在傾聽的用戶端。
就這樣,程式寫完了,範例在這裡。
========================================================================
後記:
SignalR 用了OWIN這個 .net 的輕量級小組件,拋棄了龐大的.NET Framework,這其實是很有趣的事情,他再一次的說明了資訊界~天下合久必分分久必合~的道理,以前大家想要一組完整的framework(Java or .NET),覺得寫程式拼拼裝裝的很辛苦。現在又覺得framework太大了,而且有相依性的問題,所以又想要自由一點,自己兜出想要的解決方案。
為何會有這樣的改變呢? 過去不可行的,為何現在可行了??? 我想開發工具越來越便利是其中之一的原因,以前(1999年之前)開發人員在沒有framework的情況下,想要蒐集需要的套件很累,現在有Google、有stackoverflow、有NuGet...事情變簡單了,大家就想要提高自由度了,相形之下,一整套Framework似乎就太龐大了。
前端開發技術也是,以前大家想要total solutions,現在JavaScript Framework喜歡自己兜,服務端開發技術也是,以前想要制定一整套的服務描述和查找方法,所以有Web Services和WSDL,現在大家把這些丟了,然後重來一次,就有了RESTful、Web API、JSON、和SignalR這類的技術整合和應用...
天下合久必分、分久必合,所以我開始收斂地不太敢再說趨勢和所謂的主流,因為....你只要Coding的生涯夠長,會發現所有的開發技術,終將都會改變、只要你能活得夠久,終將目睹某個開發技術的興起與消逝。
留言