一步一步學習SignalR進行實時通信_5_Hub
標簽(空格分隔): SignalR
前言
上一講,我們簡單的介紹了下Hub的配置以及實現方法,這一將我希望把更多的細節梳理清楚,不至於讓大家在細節上面摸不着頭腦,理解深了,那么做項目自然就會相對輕松一些。
Hub命名規則
Hub與PersistentConnection很大的區別就是我們可以自己定義我們自己的方法,取我們想取得名字。
Hub的前台調用后台方法的命名規則遵循駱駝命名法,如果不遵循該約定,那么在程序中很有可能報錯,在.net中約定大於配置已經是被人們普遍接受的了,它的好處是免去了大量的配置文件,而用一個公用的約定來完成,每個人只要遵循這個約定就不會出簍子。
比如在后台有這么一個方法
public void SendMessageByUserName(string userName)
{
...
}
那么在前台通過hub.server.sendMessageByUserName("name")
調用
如果后台方法改為
public void sendMessageByUserName(string userName)
{
...
}
在前台則用hub.server.sendmessageByUserName("name")
調用以此類推
在后台調用前台方法則無此約定,不區分大小寫。因此假設后台你通過Clients.Caller.testHtmlClient();
調用前台的方法前台你可以寫為hub.client.testHtmlClient()
,也可以寫為hub.client.testhtmlclient()
甚至可以寫為hub.client.teStHtMlClIENT()
Hub封裝好的常用方法
假如我希望給指定姓名的人發送信息,Hub可以通過唯一的ConnectionId號發送給指定客戶端,但是我們一般都是根據數據庫中保存用戶名或者數據庫每條記錄的Id進行數據操作。我們希望根據用戶名來發送,那么我假設有一個字典保存了ConnectionId和UserName的對應關系
public class MySecondHub : Hub
{
private IDictionary<string, string> _userNames;
public MySecondHub()
{
//TODO:初始化UserNames
}
public void SendMessageByUserName(string userName)
{
//取到所有名字為那么的用戶
IList<string> users = _userNames.Where(u => u.Value == userName).Select(u => u.Key).ToList();
Clients.Clients(users).sendMessage("Hi!");
}
}
那么在html頁面我們可以通過 hub.server.sendMessageByUserName()
調用
<script type="text/javascript">
$(function () {
//創建一個hub服務
var hub = $.connection.myFirstHub;
$.connection.hub.start()
.done(function () {
alert("連接成功!");
})
$("#sayHello").click(function () {
hub.server.sendMessageByUserName("Jake");
});
hub.client.sendMessageByUserName = function(){
...
};
});
</script>
我們也可以修改前台調用方法的名字
...
//在前台可以通過sendMessageToGroup()調用
[HubMethodName("SendMessageToGroup")]
public void SendMessageByGroupName(string groupName)
{
Clients.Group(groupName);
}
這樣在客戶端我們就可以通過sendMessageToGroup()
調用SendMessageByGroupName()
方法了。
同時,我們傳遞的參數但可以是字符串也可以是復雜的類型,如:
public class Person
{
public string Name { get; set; }
public int Age { get; set; }
}
public void SayHi(string name,string message)
{
var person = new Person(){Name = name,Message = message};
Clients.Others.sayHi(person);
}
前台代碼,點擊id為sayHello的按鈕觸發
...
$("#sayHello").click(function () {
hub.server.sayHi("jake","hah~");
});
hub.client.sayHi = function(person) {
$('#chat').append('<li><strong>' + person.Message + '</strong>:' + person.Name + '</li>');
};
...
之前我們講到Client.Others.doSomething();
可以調用給報包括自己的所有其他客戶端doSomething()方法,Hub還有許多其他的方法供我們調用
Hub常用方法解釋
- Clients.Caller:可以與調用者進行通信
- Clients.Others:可以與除了自己以外所有連接上此Hub的客戶端的通信
- Clients.All:可以與所有連接上此Hub的客戶端通信
- Clients.OthersInGroup:可以與指定組以外的其他連接到Hub的客戶端通信
- Clients.Client:可以與給指定ConnectionId的客戶端進行通信
- Clients.AllExcept:可以與所有連接上此Hub但是除去指定ConnectionId以外的客戶端通信
- Clients.Group:可以與在指定組的客戶端通信
- Clients.User:可以與指定的userId進行通信
當然他們還有一些重載方法,這里就不一一介紹了,自己去試驗下就能明白了。
PS:這里補充一個小知識,在MVC中已經實現了獲取默認的UserId方法
public class PrincipalUserIdProvider : IUserIdProvider
{
public string GetUserId(IRequest request)
{
if (request == null)
throw new ArgumentNullException("request");
if (request.User != null && request.User.Identity != null)
return request.User.Identity.Name;
else return (string) null;
}
}
很多時候我們可能需要自己實現自己的方法,比如userId為登陸的userName,那么我們可以實現IUserIdProvider接口
public class CookiesUserIdProvider : IUserIdProvider
{
public string GetUserId(IRequest request)
{
if (request == null)
throw new ArgumentNullException("request");
Cookie cookie;
if (request.Cookies.TryGetValue("UserName", out cookie))
{
return cookie.Value;
}
else
{
return null;
}
}
}
當然我們還要告訴我們的項目使用我們自定義的提供器,而不是默認的,我們只需要在程序一開始,也就是Global中注冊代碼保證程序啟動時調用即可。
public class MvcApplication : System.Web.HttpApplication
{
protected void Application_Start()
{
...
//注冊我們自己的Id提供器
GlobalHost.DependencyResolver.Register(typeof (IUserIdProvider), () => new CookiesUserIdProvider());
}
}
}
保持狀態
在hub中可以通過hub.state
保存用戶的狀態
后台通過Client.Caller
獲取前台傳遞來的參數運行項目斷點,可以看到接收到的數據
參數名可以任意寫,它是dynamic類型
前后台交互
難道保存狀態只有這個用處嗎?當然不止,這個狀態還可以在某些情況下起到前后台交互的作用。
后台我們讓Age++
然后前台在回調方法中我們在控制台中打印age,如果打印的是24,那么證明前后台數據能進行很好的交互而不僅僅是保存一個狀態那么簡單。
點擊按鈕后 通過firebug在控制台中可以看到打印出的是24
結束語
今天的文章知識點可能較零散,因為並沒有一個實際例子來連接所有的知識,明天開始放假了,如果有時間的話希望能講一個小例子來鞏固一下。
由於今天學習的都是些小細節,就不提供源碼了。
本文發布至作業部落