上周五最後一天在公司上班,無聊之余就想做點什麼.介於之前有人讓我做個簡易版的在線聊天的,於是乎就打算花一天時間來弄下關於SignalR的簡單教程制作一個在線的聊天的。
1:前端用了國產的一個MVVM框架 avalon 的早期版本和 layer 插件(具體怎麼用這裡就不介紹了,需要了解的自行百度)
2:MVC項目裡面新增一個Hub 的繼承類 ChatHub , 標簽HubName 類似於一個重命名的效果
3:OnlineCache 類的作用是定義了一個KEY和VALUE主要用於記錄用戶名稱和Signalr自動生成的KEY關系
4 : Startup.cs 裡記得注冊下 app.MapSignalR();
[HubName("customhub")]
public class ChatHub : Hub
{
/// <summary> /// 發送信息/// </summary> /// <param name=""></param> /// <returns></returns>
public void Send(string name, string message)
{
Clients.All.addNewMessageToPage(name, message);
}
/// <summary> /// 頁面打開創建Signalr對象時由客戶端調用,然後服務端將已經存在的用戶列表,推送回客戶端用於刷新在線用戶列表/// </summary> /// <param name=""></param> /// <returns></returns>
public void Push(string name)
{
if (!OnlineCache.dicSignalrs.ContainsKey(base.Context.ConnectionId))
OnlineCache.dicSignalrs.Add(base.Context.ConnectionId, name);
else
{
OnlineCache.dicSignalrs.Remove(base.Context.ConnectionId);
OnlineCache.dicSignalrs.Add(base.Context.ConnectionId, name);
}
///這裡是將在線人員列表推送回客戶端
Clients.All.subscribeUsers(name,OnlineCache.OnlineToList());
}
//
// 摘要:
// Called when the connection connects to this hub instance.
//
// 返回結果:
// A System.Threading.Tasks.Task
public override Task OnConnected()
{
return base.OnConnected();
}
//
// 摘要:
// Called when a connection disconnects from this hub gracefully or due to a timeout.
//
// 參數:
// stopCalled:
// true, if stop was called on the client closing the connection gracefully; false,
// if the connection has been lost for longer than the Microsoft.AspNet.SignalR.Configuration.IConfigurationManager.DisconnectTimeout.
// Timeouts can be caused by clients reconnecting to another SignalR server in scaleout.
//
// 返回結果:
// A System.Threading.Tasks.Task
/// <summary>
/// 離線觸發
/// </summary>
/// <param name="stopCalled"></param>
/// <returns></returns>
public override Task OnDisconnected(bool stopCalled)
{
if (OnlineCache.dicSignalrs.ContainsKey(base.Context.ConnectionId))
{
var name = OnlineCache.dicSignalrs[base.Context.ConnectionId];
OnlineCache.dicSignalrs.Remove(base.Context.ConnectionId);
///離線後將在線人員移除的通知 推送到客戶端
Clients.All.removeUser(name, OnlineCache.OnlineToList());
}
return base.OnDisconnected(stopCalled);
}
//
// 摘要:
// Called when the connection reconnects to this hub instance.
//
// 返回結果:
// A System.Threading.Tasks.Task
public override Task OnReconnected()
{
return base.OnReconnected();
}
}
public class OnlineCache
{
public OnlineCache() {
}
public string Key { set; get; }
public string Value { set; get; }
static OnlineCache()
{
if (dicSignalrs == null)
dicSignalrs = new Dictionary<string, string>();
}
public static Dictionary<string, string> dicSignalrs;
/// <summary>
/// 提取list
/// </summary>
/// <returns></returns>
public static List<OnlineCache> OnlineToList() => dicSignalrs.Select(o => new OnlineCache() { Key = o.Key, Value = o.Value }).ToList();
}
前端JS腳本
@{
Layout = null;
}
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width" />
<title>Index</title>
<link href="~/Content/bootstrap.min.css" rel="stylesheet" />
<link href="~/Content/Site.css" rel="stylesheet" />
<link href="~/Scripts/layer-v2.4/layer/skin/layer.css" rel="stylesheet" />
<script src="~/Scripts/jquery-1.10.2.min.js"></script>
<script src="~/Scripts/Avalon/json2.js"></script>
<script src="~/Scripts/jquery.signalR-2.2.1.min.js"></script>
<script src="~/Scripts/layer-v2.4/layer/layer.js"></script>
<script src="~/Scripts/Avalon/avalon.js"></script>
<script src="/signalr/hubs"></script>
<script>
var onlines = [];
var chat;
$(function () {
vm.init();
});
var vm =
avalon.define({
$id: "online",
sendname: "所有在線用戶",
customname: "",
onlines: [],
logs: [],
authorize: false,
sendText: "",
firstload: false,
init: function () {
layer.prompt({
title: '輸入聊天昵稱,並確認',
formType: 0
}, function (name) {
layer.msg('聊天室內容加載中', {
time: 1000
});
vm.customname = name;
vm.authorize = true;
vm.callbackmessage();
});
},
connection: function () {
$.connection.hub.start().done(function () {
///首次頁面加載注冊完畢後直接把用戶名發到後台建立用戶列表
if (!vm.firstload) {
vm.firstload = true;
chat.server.push(vm.customname);
}
$('#btnSend').click(function () {
if (!vm.authorize) {
layer.msg("沒有通過授權不能進行聊天");
return;
}
//**這裡主要是用於發送信息
chat.server.send(vm.customname, $('#message').val());
$('#message').val('').focus();
});
});
vm.getOnlineUser();
},
callbackmessage: function () {
chat = $.connection.customhub;
//**有用戶登陸 這裡會接收到服務端推送過來的消息name是上線用戶名稱 users是在線用戶列表 直接綁定mvvm的onlines刷新列表
chat.client.subscribeUsers = function (name,users) {
layer.tips(name + " 上線", '#btnSend', {
tips: [1, '#3595CC']
});
vm.onlines = users;
};
chat.client.removeUser = function (name, users) {
layer.tips(name + " 離線", '#btnSend', {
tips: [1, 'red']
});
vm.onlines = users;
};
chat.client.addNewMessageToPage = function (name, message) {
vm.logs.push({ name: name, message: message });
};
vm.connection();
}
});
</script>
</head>
<body ms-controller="online">
<div class="col-sm-2 col-md-2 col-lg-2">
<label>在線用戶列表</label>
<br />
<div class="list-group">
<a href="#" ms-repeat="onlines" class="list-group-item">
{{el.Value}}
</a>
</div>
</div>
<div class="col-sm-5 col-md-5 col-lg-5">
<textarea id="message" placeholder="輸入發送內容" class="form-control" ms-duplex="sendText"></textarea>
<br />
<br />
<div class="row col-sm-12 col-md-12 col-lg-12">
<div class="table-scrollable" >
<table class="table table-bordered table-hover text-center">
<thead>
<tr>
<th class="col-sm-4">發送人</th>
<th class="col-sm-8">內容</th>
</tr>
<tr href="#" ms-repeat="logs">
<th class="col-sm-4">{{el.name}}</th>
<th class="col-sm-8">{{el.message}}</th>
</tr>
</thead>
</table>
</div>
</div>
</div>
<div class="col-sm-3 col-md-3 col-lg-3">
<br />
<div class="row">
<input class="btn btn-primary col-sm-5 col-md-5 col-lg-5" value="發送消息" id="btnSend" type="button" />
</div>
<br />
<br />
<div class="row">
<label>賬號昵稱:</label><label>{{customname}}</label>
</div>
<br />
<br />
<div class="row">
<label>發送對象:</label><label>{{sendname}}</label>
</div>
</div>
<div class="row">
<div class="col-sm-offset-11 col-sm-1 pull-right" id="tip">
</div>
</div>
</body>
</html>