翻译自:http://www.codeproject.com/Articles/562023/Asp-Net-SignalR-Chat-Room (在这里能够下载到实例的源码)
javascript
Asp.Net SignalR 聊天室html
简单介绍:
最近微软向ASP.NET Web Application Framework中添加了不少的新特性,SignalR是其中比较显著的特性之一,它是用来建立实时的应用程序的,例如:社交应用(social application)、多人游戏、新闻天气等,在实时的应用程序中,一旦内容能够产生立刻就会被推送给用户,它为远程呼叫(remote procedure calls)提供一个asp.net API,用来在服务器端经过.net代码调用一个客户端浏览器中的js方法。java
web应用程序经过请求处理模型来工做,浏览器或者其余的代理发送一个请求,而后服务器端为请求提供相应在这个模型当中,服务器在没有被请去I的时候不能作出响应,然而在实时的应用程序服务器上,最新的可用内容会被推送到客户端你能够经过使用ASP.NET SignalR API 来达到这一特性jquery
为了解释 SignalR Web API ,在这篇文章中,我会建立一个能够群组聊天也能够私聊的聊天程序,你须要用VS2012 来建立这个项目
你在这个网站能够获取更多的信息http://www.asp.net/signalrweb
让咱们开始吧:
在VS中建立一个新的应用程序项目(web application project ),建立好了之后,右键——添加新项——选择SignalR Hub Class ,命名以后点击添加按钮,它会自动添加 Hub 类,须要的引用,还有脚本。浏览器
注册Hub URL
为了使用SignalR API,咱们须要注册 ~/signalr/hubs URL,在你的解决方案中添加global.asax文件,在Application_Start方法中用RouteTable.Routes.MapHubs()来注册 Hub URL缓存
public class Global : System.Web.HttpApplication
{
protected void Application_Start(object sender, EventArgs e)
{
// Register the default hubs route: ~/signalr/hubs
RouteTable.Routes.MapHubs();
}服务器
} app
Hub 类
ChatHub 类必须继承自Microsoft.AspNet.SignalR.Hub 类,Hub 类暴露出一些属性和方法,你能够经过Clients属性与保持连接的客户端交流
你能够获得正在调用方法使用Contextde 客户端的信息,你也能够经过Groups属性来管理组。asp.net
public abstract class Hub : IHub, IDisposable
{
public HubConnectionContext Clients { get; set; }
public HubCallerContext Context { get; set; }
public IGroupManager Groups { get; set; }
public virtual Task OnConnected();
public virtual Task OnDisconnected();
public virtual Task OnReconnected();
}
子类能够重写Onconnected,OnDisconnected方法,这个对事件触发一些动做是很是有用的,ChatHub 类是Hub类的子类,在接下来的部分咱们来讨论它们的方法
public class ChatHub : Hub
{
public void Connect(string userName);
public void SendMessageToAll(string userName, string message);
public void SendPrivateMessage(string toUserId, string message);
public override System.Threading.Tasks.Task OnDisconnected();
.
.
.
}
客户端在他想进入聊天室的时候会调用Connect方法,调用SendMessageToAll方法,他能够向聊天室中保持链接的全部人
经过调用 SendPrivateMessage 方法,key与单独的一个客户端聊天
客户端的代理(Proxy)
在项目中添加index.html 页面,引用JQuery,SignalR、还有自动生成的hubs(?不知道这个指什么)
<script src="http://www.codeproject.com/Scripts/jquery-1.8.2.min.js%22%3E%3C/script>
<!--Reference the SignalR library. -->
<script src="http://www.codeproject.com/Scripts/jquery.signalR-1.0.0.js%22%3E%3C/script>
<!--Reference the autogenerated SignalR hub script. -->
<script src="http://www.codeproject.com/signalr/hubs%22%3E%3C/script>
在客户端,你须要建立一个hub 代理(hub proxy)并启动它,一能够经过$.connection.yourHubClass来建立它$.connection.hub.start() 来启动它
<script type="text/javascript">
$(function () {
// Declare a proxy to reference the hub.
var chatHub = $.connection.chatHub;
registerClientMethods(chatHub);
// Start Hub
$.connection.hub.start().done(function () {
registerEvents(chatHub)
});
});
</script>
在这里咱们须要注意的是自动生成的Hub proxy的命名方法,咱们在服务器端用Camel命名法给ChatHub类命名,可是在客户端咱们获得的是用little camel 方式命名的,就像$.connection.chatHub
链接到聊天室
用户成功的连接以后发送他的名称就能够链接到聊天室,咱们会给他发送一个列表,和一些存在咱们程序中的最近的聊天记录在ChatHub类中的第一个方法就是Connect
public void Connect(string userName)
{
var id = Context.ConnectionId;
if (ConnectedUsers.Count(x => x.ConnectionId == id) == 0)
{
ConnectedUsers.Add(new UserDetail { ConnectionId = id, UserName = userName });
// send to caller
Clients.Caller.onConnected(id, userName, ConnectedUsers, CurrentMessage);
// send to all except caller client
Clients.AllExcept(id).onNewUserConnected(id, userName);
}
}
经过Context.ConnectionId属性拿到调用Connect方法的用户的链接Id,在已有的连接列表汇总核对是否已经存在该用户的连接,如今咱们还要作两件事,首先,咱们要将已链接的客户端的列表和最近的聊天记录发送给想要连接的客户端,而后咱们要同通知其余的用户有新人加进来了,咱们能够经过Clients.Caller属性来很方便的调用想要链接到聊天室的客户端的方法:
// send to caller
Clients.Caller.onConnected(id, userName, ConnectedUsers, CurrentMessage);
要通知其余的连接在聊天室的人,可是咱们又不想调用新加入的人的方法,能够用Clients的AllExcept属性,它能够按照你的意愿来排除一些客户端
// send to all except caller client
Clients.AllExcept(id).onNewUserConnected(id, userName);
定义/发布 你在服务器端调用的客户端的方法,作法是声明Clients.Caller.onConnected(...) 和 Clients.AllExcept(id).onNewUserConnected(...)
???You can define your methods using chatHub.client.yourMethodName at client side.
// Calls when user successfully logged in
chatHub.client.onConnected = function (id, userName, allUsers, messages) {
.
.
.
}
// On New User Connected
chatHub.client.onNewUserConnected = function (id, name) {
AddUser(chatHub, id, name);
}
用chatHub.server.yourMethod声明, 在客户端,你能够调用服务器端的方法。
chatHub.server.connect(name);
在聊天室中发送消息:
在出聊天室中,用户输入的消息会广播给全部正在链接中的用户,在服务器端的ChatHub类中,写用Clients.All.messageReceived来写 SendMessageToAll方法,
messageReceived是一个客户端的方法。
public void SendMessageToAll(string userName, string message)
{
// store last 100 messages in cache
AddMessageinCache(userName, message);
// Broad cast message
Clients.All.messageReceived(userName, message);
}
在客户端引起messageReceived 方法,这个方式只是简单的用JQuery将消息加入到聊天区域
chatHub.client.messageReceived = function (userName, message) {
AddMessage(userName, message);
}
在写好了客户端和服务器端的方法之后,如今咱们要在客户端来注册按钮的点击事件,在用户点击按钮的时候,就会调用服务器端的sendMessageToAll方法,它会广播消息给全部处于链接状态的客户端
$('#btnSendMsg').click(function () {
var msg = $("#txtMessage").val();
if (msg.length > 0) {
var userName = $('#hdUserName').val();
chatHub.server.sendMessageToAll(userName, msg);
$("#txtMessage").val('');
}
});
私聊模式
你也能够经过双击客户端的名称实现私聊,私聊的时候咱们不用发信息给全部正在链接的客户端,在私聊的时候,只有两个客户端之间进行通话,因此在发送私人信息的时候,
发送人要调用sendPrivateMessage 方法
public void SendPrivateMessage(string toUserId, string message)
{
string fromUserId = Context.ConnectionId;
var toUser = ConnectedUsers.FirstOrDefault(x => x.ConnectionId == toUserId) ;
var fromUser = ConnectedUsers.FirstOrDefault(x => x.ConnectionId == fromUserId);
if (toUser != null && fromUser!=null)
{
// send to
Clients.Client(toUserId).sendPrivateMessage(fromUserId, fromUser.UserName, message);
// send to caller user
Clients.Caller.sendPrivateMessage(toUserId, fromUser.UserName, message);
}
}
断开链接:
在浏览器关闭的时候,SignalR API 调用 OnDisconnected 方法,在你的ChatHub类中重写这个方法,
在这个方法中将断开链接的客户端从缓存结合中删除而且向其余的用户发送一个提示。
public override System.Threading.Tasks.Task OnDisconnected()
{
var item = ConnectedUsers.FirstOrDefault(x => x.ConnectionId == Context.ConnectionId);
if (item != null)
{
ConnectedUsers.Remove(item);
var id = Context.ConnectionId;
Clients.All.onUserDisconnected(id, item.UserName);
}
return base.OnDisconnected();
}