ASP.NET SignalR 是爲 ASP.NET 開發人員提供的一個庫,能夠簡化開發人員將實時 Web 功能添加到應用程序的過程。實時 Web 功能是指這樣一種功能:當所鏈接的客戶端變得可用時服務器代碼能夠當即向其推送內容,而不是讓服務器等待客戶端請求新的數據。html
下面介紹一下本人在Android手機開發中的使用,開發編譯環境使用Xamarin。手機做爲一個客戶端接入服務器。web
首先,在Xamarin中創建Android App,添加SignalR Client開發包,目前最新版本爲2.2.0.0。服務器
而後,添加FireHub類。FireHub類的實現代碼以下:app
using System; using System.Collections.Generic; using System.Text; using System.ComponentModel; using Microsoft.AspNet.SignalR; using Microsoft.AspNet.SignalR.Client; using Microsoft.AspNet.SignalR.Client.Hubs; using NicoDemo.Model; namespace Nico.Android.SignalR { public class FireHub { #region 變量聲明 public HubConnection _connection=null; private IHubProxy _proxy=null; public bool IsConnected = false; public delegate void ReceiveMessageDelegate(string msg); public event ReceiveMessageDelegate Receive=null; public delegate void HubCloseDelegate(); public event HubCloseDelegate CloseHub = null; public delegate void HubStatusChangedDelegate(int state,string msg); public event HubStatusChangedDelegate StateChanged = null; public delegate void AddWebMessageDelegate(WebMessage wm); public event AddWebMessageDelegate AddWebMessage = null; #endregion #region 初始化 public FireHub() { IsConnected = false; _connection = null; _proxy = null; } public string Dispose() { try { if (_connection != null) { try { _connection.Stop(); } catch { } _connection = null; } if (_proxy != null) _proxy = null; IsConnected = false; return ""; } catch(Exception err) { return string.Format("({0}-{1})",err.Message + err.StackTrace); } } #endregion #region HUB事件 void _connection_Closed() { if (CloseHub != null) CloseHub(); IsConnected = false; } void _connection_Received(string obj) { if (Receive != null) Receive(obj); } #endregion #region HUB客戶端方法 public bool Connect(string url,int timeout=5000) { try { if (_connection == null) { _connection = new HubConnection(url);//,queryString); _connection.Received += _connection_Received; _connection.Closed += _connection_Closed; _connection.StateChanged += _connection_StateChanged; _proxy = _connection.CreateHubProxy("notifyHub"); } if (_connection.Start().Wait(timeout))//同步調用 { IsConnected = true; return true; } else { IsConnected = false; _connection.Dispose(); _connection = null; _proxy = null; return false; } } catch { return false; } } void _connection_StateChanged(StateChange obj) { try { switch (obj.NewState) { case ConnectionState.Disconnected: IsConnected = false; if (_connection != null) { _connection.Dispose(); _connection = null; _proxy = null; } if (StateChanged != null) StateChanged(0,""); break; } } catch(Exception err) { if (StateChanged != null) StateChanged(1, "_connection_StateChanged:"+err.Message); } } public bool ConnectToServer(UsersEntity user,int timeout=5000) { try { if (_connection == null || _proxy == null||!IsConnected) return false; return _proxy.Invoke("connect",user.ID,user.Name,user.TypeID).Wait(timeout); } catch(Exception err) { if (StateChanged != null) StateChanged(1, "ConnectToServer:"+err.Message); return false; } } public bool SendMessageToAll(UsersEntity user,string message, int timeout = 5000) { try { if (_connection == null || _proxy == null || !IsConnected) return false; _proxy.Invoke("sendMessageToAll", user.ID,user.Name,user.TypeID,message);//.Wait(timeout); return true; } catch(Exception err) { if (StateChanged != null) StateChanged(1,"SendMessageToAll:"+ err.Message); return false; } } public bool SendMessageToPrivate(string toConnID, string message) { try { if (_connection == null || _proxy == null || !IsConnected) return false; _proxy.Invoke("sendPrivateMessage", toConnID, message); return true; } catch(Exception err) { if (StateChanged != null) StateChanged(1, "SendMessageToPrivate:"+err.Message); return false; } } #endregion #region 公共函數 public bool SendToWeb(UsersEntity user,int timeout=5000) { try { // <th>事件時間</th> //<th>事件類型</th> //<th>發送者</th> //<th>單位編號</th> //<th>信息內容</th> if (!SendMessageToAll(user,"connect test", timeout)) return false; return true; } catch (Exception err) { if (StateChanged != null) StateChanged(1, "SendToWeb:"+err.Message); return false; } } #endregion } public class HubUser { [DisplayName("鏈接ID")] public string ConnectionId { get; set; } [DisplayName("用戶ID")] public int UserID { get; set; } [DisplayName("用戶名")] public string UserName { get; set; } [DisplayName("用戶類型")] public int TypeID { get; set; } [DisplayName("連入時間")] public DateTime ConnectionTime { get; set; } public HubUser(string connID,int userID, string name,int typeID) { ConnectionId = connID; UserID = userID; UserName = name; TypeID = typeID; ConnectionTime = DateTime.Now; } } public class WebMessage { public string ToConnID{get;set;} public DateTime MessageDate{get;set;} public string MessageContent { get; set; } public bool IsAnswer{get;set;} public int RepeatCounts { get; set; } public bool IsRemovable { get; set; } public WebMessage() { ToConnID=string.Empty; MessageDate=DateTime.Now; MessageContent = string.Empty; IsAnswer=false; RepeatCounts = 0; IsRemovable = false; } } }
最後,在Activity中增長對FireHub的使用,參考代碼以下:ide
public class SignalRActivity : Activity { private FireHub _fireHub = null; private UsersEntity _user = null; protected override void OnCreate (Bundle bundle) { base.OnCreate (bundle); // Create your application here SetContentView(Resource.Layout.SignalR); _user = new UsersEntity (); Button btnConnectHub = FindViewById<Button> (Resource.Id.btnConnectHub); btnConnectHub.Text = "監控網站鏈接"; btnConnectHub.Click += btnConnectHubClick; } protected void btnConnectHubClick(object sender,EventArgs e) { try { if (_fireHub != null) { StopHub(); lock (_syncUser) { _hubUser.Clear(); } //UpdateList(); } else { if (HubReconnect(false)) { RunOnUiThread(new Action(()=>{ _txtView.Text=string.Format("{0}: 實時網站鏈接成功", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"));})); } else { RunOnUiThread(new Action(()=>{ _txtView.Text=string.Format("{0}: 實時網站鏈接失敗", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"));})); } } } catch (Exception err) { //FormMain.STAErrLogger.Write(string.Format("{0}({1}-{2})", err.Message, "FormMain", "btnConnectHub_Click")); } } #region HUB管理 bool HubReconnect(bool checkNull=true) { bool bRet = false; bool isUpdate = false; //從新鏈接到服務網站 if (!checkNull || _fireHub != null) { if (_fireHub != null) _fireHub.IsConnected = false; if (!ConnectHubServer()) { } else { bRet = true; } isUpdate = true; } return bRet; } public bool ConnectHubServer() { try { if (_fireHub == null) _fireHub = new FireHub(); else { if (_fireHub.IsConnected) return true; } if (!_fireHub.Connect("http://your service web", 5000)) { RunOnUiThread(new Action(()=>{ _txtView.Text="實時報警服務網站不在服務狀態";})); if (_fireHub != null) { string strDispose = _fireHub.Dispose(); if (!string.IsNullOrEmpty(strDispose)) { //FormMain.STAErrLogger.Write(string.Format("{0}({1})", "ConnectHubServer-0", strDispose)); } } _fireHub = null; return false; } else { if (_fireHub.ConnectToServer(_user)) { _fireHub.Receive -= _fireHub_Receive; _fireHub.Receive += _fireHub_Receive; _fireHub.CloseHub -= _fireHub_CloseHub; _fireHub.CloseHub += _fireHub_CloseHub; _fireHub.StateChanged -= _fireHub_StateChanged; _fireHub.StateChanged += _fireHub_StateChanged; _fireHub.AddWebMessage -= _fireHub_AddWebMessage; _fireHub.AddWebMessage += _fireHub_AddWebMessage; if (_webMessageManage == null) { _webMessageManage = new WebMessageManage(); _webMessageManage.WebMessageCallback += _webMessageManage_WebMessageCallback; } RunOnUiThread(new Action(()=>{ _txtView.Text="成功鏈接到實時報警服務網站";})); } else { RunOnUiThread(new Action(()=>{ _txtView.Text="鏈接到實時報警服務網站失敗,請從新嘗試";})); string strDispose = _fireHub.Dispose(); if(!string.IsNullOrEmpty(strDispose)) { } _fireHub = null; return false; } } return true; } catch (Exception err) { return false; } } #endregion #region FireHub事件實現 void _fireHub_Receive(string msg) { try { HubMessage hm = new HubMessage(); hm = Newtonsoft.Json.JsonConvert.DeserializeObject<HubMessage>(msg); if (hm == null) return; if (hm.M == "onConnected") { #region 客戶端鏈接成功後的反饋消息 #endregion } else if (hm.M == "onNewUserConnected") { #region 有新的客戶端接入 #endregion } else if (hm.M == "onUserDisconnected") { #region 客戶端斷開 #endregion } else if (hm.M == "messageReceived") { #region 定時廣播巡查 #endregion } else if (hm.M == "sendCallbackMessage") { #region 私人消息發出成功後,返回反饋消息 #endregion } else if (hm.M == "sendPrivateMessage") { #region 接收到私人消息 #endregion } } catch (Exception err) { RunOnUiThread(new Action(()=>{ _txtView.Text="HUB Error:" + err.Message + err.Source; })); } } void _fireHub_CloseHub() { StopHub(); } public void StopHub() { try { RunOnUiThread(new Action(()=>{ _txtView.Text="實時報警服務網站關閉"; })); if (_fireHub == null) return; string strDispose = _fireHub.Dispose(); if (!string.IsNullOrEmpty(strDispose)) { } _fireHub = null; RunOnUiThread(new Action(()=>{ ChangeHubButtonStatus(); })); } catch (Exception err) { } } void _webMessageManage_WebMessageCallback(int flag) { try { if (flag == 0) { if ((DateTime.Now - _dtHubReconnect).TotalMinutes < 30) { return; } RunOnUiThread(new Action(()=>{ })); //從新鏈接到服務網站 if(HubReconnect(true)) { _dtHubReconnect = DateTime.Now; } } } catch (Exception err) { } } void _fireHub_AddWebMessage(WebMessage wm) { try { if (_webMessageManage != null) { _webMessageManage.AddMessage(wm); } } catch (Exception err) { } } void _fireHub_StateChanged(int state, string msg) { try { switch (state) { case 0://斷開鏈接了 { RunOnUiThread(new Action(()=>{ _txtView.Text="HUB掉線"; })); StopHub(); } break; case 1://HUB異常 { RunOnUiThread(new Action(()=>{ _txtView.Text=msg; })); StopHub(); } break; } } catch (Exception err) { } } #endregion }
完成之後編譯經過,而且可以實現服務器和客戶端的實時消息推送。函數