下列步骤将使用 Visual Studio 2013 创建 ASP.NET 空 Web 应用程序并添加那么 SignalR 和 jQuery.UI 的库︰
-
在 Visual Studio 中创建一个 ASP.NET Web 应用程序。

-
在新的 ASP.NET 项目窗口中,保留空选定,然后单击创建项目.

-
在解决方案资源管理器中,右键单击项目,选择添加|那么 SignalR 集线器类 (v2)。将类命名为MoveShapeHub.cs并将其添加到项目。此步骤将创建MoveShapeHub类,并向项目中添加一组脚本文件和支持那么 SignalR 的程序集引用。
注︰你也可以向项目添加那么 SignalR 通过单击工具 |库包管理器 |程序包管理器控制台和运行命令︰
install-package Microsoft.AspNet.SignalR .
如果你使用控制台来添加那么 SignalR,那么 SignalR 集线器类作为一个单独的步骤之后创建您添加那么 SignalR。
-
单击工具|库包管理器 |程序包管理器控制台。在软件包管理器窗口中,运行以下命令︰
Install-Package jQuery.UI.Combined
这将安装 jQuery UI 库,您将使用对形状进行动画处理。
-
在解决方案资源管理器中展开脚本节点。JQuery,jQueryUI,那么 SignalR 的脚本库是在项目中可见。

创建基本应用程序
在本节中,我们将创建一个浏览器应用程序,在每个鼠标移动事件时向服务器发送形状的位置。服务器然后广播此信息给所有其他连接的客户端,它是收到。我们会扩大这个在后面几节中的应用。
-
如果没有已创建 MoveShapeHub.cs 类,在解决方案资源管理器中,右键单击该项目,并选择添加,上课......。MoveShapeHub类的名称并单击添加.
-
新的MoveShapeHub类中的代码替换为下面的代码。
using Microsoft.AspNet.SignalR;
using Newtonsoft.Json;
namespace MoveShapeDemo
{
public class MoveShapeHub : Hub
{
public void UpdateModel(ShapeModel clientModel)
{
clientModel.LastUpdatedBy = Context.ConnectionId;
// Update the shape model within our broadcaster
Clients.AllExcept(clientModel.LastUpdatedBy).updateShape(clientModel);
}
}
public class ShapeModel
{
// We declare Left and Top as lowercase with
// JsonProperty to sync the client and server models
[JsonProperty("left")]
public double Left { get; set; }
[JsonProperty("top")]
public double Top { get; set; }
// We don't want the client to get the "LastUpdatedBy" property
[JsonIgnore]
public string LastUpdatedBy { get; set; }
}
}
MoveShapeHub 级以上是那么 SignalR 中心执行。在入门那么 SignalR的教程,集线器有客户将直接调用方法。在这种情况下,客户端会发送一个包含新对象的形状到服务器,然后获取广播给所有其他连接的客户端的 X 和 Y 坐标。那么 SignalR 将自动序列化此对象使用 JSON。
将发送到客户端 (ShapeModel ) 的对象包含成员来存储形状的位置。该对象在服务器上的版本还包含成员来跟踪哪个客户端的数据存储,所以,给定客户端将不会发送自己的数据。此成员使用JsonIgnore 属性以防止它被序列化并发送到客户端。
在应用程序启动时启动集线器
-
接下来,我们将设置映射到该集线器,当应用程序启动。在那么 SignalR 2,这是通过添加浩然启动类,将调用MapSignalR 时浩然启动时执行启动类的Configuration 方法。类被添加到使用OwinStartup 程序集属性的浩然的启动进程。
在解决方案资源管理器中,右键单击项目,然后单击添加|欧文真启动类。启动的类的名称并单击确定.
如下所示更改 Startup.cs 的内容︰
using Microsoft.Owin;
using Owin;
[assembly: OwinStartup(typeof(MoveShapeDemo.Startup))]
namespace MoveShapeDemo
{
public class Startup
{
public void Configuration(IAppBuilder app)
{
// Any connection or hub wire up and configuration should go here
app.MapSignalR();
}
}
}
添加客户端
-
接下来,我们会添加客户端。在解决方案资源管理器中,右键单击项目,然后单击添加|新项目。在添加新项对话框中,选择Html 页。Default.html为该页命名并单击添加.
在解决方案资源管理器,右键单击页面,您只需创建并单击设置为起始页.
-
在 HTML 页面中的默认代码替换为下面的代码段。
注︰验证脚本引用以下匹配的软件包添加到您在脚本文件夹中的项目。
<!DOCTYPE html>
<html>
<head>
<title>SignalR MoveShape Demo</title>
<style>
#shape {
width: 100px;
height: 100px;
background-color: #FF0000;
}
</style>
</head>
<body>
<script src="Scripts/jquery-1.10.2.min.js"></script>
<script src="Scripts/jquery-ui-1.10.4.min.js"></script>
<script src="Scripts/jquery.signalR-2.1.0.js"></script>
<script src="/signalr/hubs"></script>
<script>
$(function () {
var moveShapeHub = $.connection.moveShapeHub,
$shape = $("#shape"),
shapeModel = {
left: 0,
top: 0
};
moveShapeHub.client.updateShape = function (model) {
shapeModel = model;
$shape.css({ left: model.left, top: model.top });
};
$.connection.hub.start().done(function () {
$shape.draggable({
drag: function () {
shapeModel = $shape.offset();
moveShapeHub.server.updateModel(shapeModel);
}
});
});
});
</script>
<div id="shape" />
</body>
</html>
上面的 HTML 和 JavaScript 代码创建称为形状的红色 Div、 启用的形状拖动行为使用 jQuery 库,并使用该形状drag 事件向服务器发送该形状的位置。
-
按 f5 键启动该应用程序。复制的页的 URL,并将其粘贴到另一个浏览器窗口。将形状拖在一个浏览器窗口;另一个浏览器窗口中的形状应移动。

添加客户端循环
由于发送的位置上每一个鼠标移动事件的形状将创建不必要的大量网络流量,从客户端消息需要被扼杀。我们将使用 javascript setInterval 函数设置了一个循环,将新的位置信息发送到服务器以固定的速度。这种循环是功能的"游戏循环",多次被调用的函数,驱动所有的游戏或其他模拟非常基本表示。
-
更新要匹配下面的代码段的 HTML 页面中的客户端代码。
<!DOCTYPE html>
<html>
<head>
<title>SignalR MoveShape Demo</title>
<style>
#shape {
width: 100px;
height: 100px;
background-color: #FF0000;
}
</style>
</head>
<body>
<script src="Scripts/jquery-1.10.2.min.js"></script>
<script src="Scripts/jquery-ui-1.10.4.min.js"></script>
<script src="Scripts/jquery.signalR-2.1.0.js"></script>
<script src="/signalr/hubs"></script>
<script>
$(function () {
var moveShapeHub = $.connection.moveShapeHub,
$shape = $("#shape"),
// Send a maximum of 10 messages per second
// (mouse movements trigger a lot of messages)
messageFrequency = 10,
// Determine how often to send messages in
// time to abide by the messageFrequency
updateRate = 1000 / messageFrequency,
shapeModel = {
left: 0,
top: 0
},
moved = false;
moveShapeHub.client.updateShape = function (model) {
shapeModel = model;
$shape.css({ left: model.left, top: model.top });
};
$.connection.hub.start().done(function () {
$shape.draggable({
drag: function () {
shapeModel = $shape.offset();
moved = true;
}
});
// Start the client side server update interval
setInterval(updateServerModel, updateRate);
});
function updateServerModel() {
// Only update server if we have a new movement
if (moved) {
moveShapeHub.server.updateModel(shapeModel);
moved = false;
}
}
});
</script>
<div id="shape" />
</body>
</html>
上述更新添加了updateServerModel 函数,调用在一个固定的频率。每当moved 标志指示是要发送的新位置数据,此函数会向服务器发送位置数据。
-
按 f5 键启动该应用程序。复制的页的 URL,并将其粘贴到另一个浏览器窗口。将形状拖在一个浏览器窗口;另一个浏览器窗口中的形状应移动。因为将节流的得到发送到服务器的消息数,动画不会出现上一节一样光滑。

添加服务器循环
在当前应用程序中,从服务器发送到客户端消息通常在收到出去。这提出了一个类似的问题,作为看了在客户端上;可以将消息发送往往比他们的需要和连接可能因此成为被水淹没。本节介绍如何更新服务器来实现一个计时器,节流孔的传出消息的速率。
-
MoveShapeHub.cs 的内容替换为下面的代码段。
using System;
using System.Threading;
using Microsoft.AspNet.SignalR;
using Newtonsoft.Json;
namespace MoveShapeDemo
{
public class Broadcaster
{
private readonly static Lazy<Broadcaster> _instance =
new Lazy<Broadcaster>(() => new Broadcaster());
// We're going to broadcast to all clients a maximum of 25 times per second
private readonly TimeSpan BroadcastInterval =
TimeSpan.FromMilliseconds(40);
private readonly IHubContext _hubContext;
private Timer _broadcastLoop;
private ShapeModel _model;
private bool _modelUpdated;
public Broadcaster()
{
// Save our hub context so we can easily use it
// to send to its connected clients
_hubContext = GlobalHost.ConnectionManager.GetHubContext<MoveShapeHub>();
_model = new ShapeModel();
_modelUpdated = false;
// Start the broadcast loop
_broadcastLoop = new Timer(
BroadcastShape,
null,
BroadcastInterval,
BroadcastInterval);
}
public void BroadcastShape(object state)
{
// No need to send anything if our model hasn't changed
if (_modelUpdated)
{
// This is how we can access the Clients property
// in a static hub method or outside of the hub entirely
_hubContext.Clients.AllExcept(_model.LastUpdatedBy).updateShape(_model);
_modelUpdated = false;
}
}
public void UpdateShape(ShapeModel clientModel)
{
_model = clientModel;
_modelUpdated = true;
}
public static Broadcaster Instance
{
get
{
return _instance.Value;
}
}
}
public class MoveShapeHub : Hub
{
// Is set via the constructor on each creation
private Broadcaster _broadcaster;
public MoveShapeHub()
: this(Broadcaster.Instance)
{
}
public MoveShapeHub(Broadcaster broadcaster)
{
_broadcaster = broadcaster;
}
public void UpdateModel(ShapeModel clientModel)
{
clientModel.LastUpdatedBy = Context.ConnectionId;
// Update the shape model within our broadcaster
_broadcaster.UpdateShape(clientModel);
}
}
public class ShapeModel
{
// We declare Left and Top as lowercase with
// JsonProperty to sync the client and server models
[JsonProperty("left")]
public double Left { get; set; }
[JsonProperty("top")]
public double Top { get; set; }
// We don't want the client to get the "LastUpdatedBy" property
[JsonIgnore]
public string LastUpdatedBy { get; set; }
}
}
上面的代码扩展了客户端添加Broadcaster 类,节流孔使用Timer 类从.NET 框架的传出消息。
由于集线器本身是暂时的 (它创建每次需要),Broadcaster 将被创建为单身人士。延迟初始化 (.NET 4 中引入) 用来推迟其创作,直到它需要确保枢纽一审完全创建之前启动计时器。
对客户的UpdateShape 函数的调用然后移出枢纽的UpdateModel 方法,以便它不再叫做立即每当收到传入的消息。相反,将向客户端消息发送速度 25 每秒调用,由_broadcastLoop 计时器从Broadcaster 类的内部管理。
最后,而不是直接调用客户端方法从集线器,Broadcaster 类需要获取对当前正在运行的枢纽 (_hubContext ) 使用GlobalHost 的引用.
-
按 f5 键启动该应用程序。复制的页的 URL,并将其粘贴到另一个浏览器窗口。将形状拖在一个浏览器窗口;另一个浏览器窗口中的形状应移动。不会有明显的差异,在浏览器中从上一节,但将节流的送到客户端的邮件数。

在客户端上添加平滑的动画
应用程序已接近完成,但我们可以做出一个更多改进,在客户端上的形状的运动是在移动中响应服务器消息。而不是由服务器给出的新位置设置形状的位置,我们将使用 JQuery UI 库animate 函数其当前和新位置之间平滑地移动形状。
-
更新客户端的updateShape 方法,看起来像下面突出显示的代码︰
<!DOCTYPE html>
<html>
<head>
<title>SignalR MoveShape Demo</title>
<style>
#shape {
width: 100px;
height: 100px;
background-color: #FF0000;
}
</style>
</head>
<body>
<script src="Scripts/jquery-1.10.2.min.js"></script>
<script src="Scripts/jquery-ui-1.10.4.min.js"></script>
<script src="Scripts/jquery.signalR-2.1.0.js"></script>
<script src="/signalr/hubs"></script>
<script>
$(function () {
var moveShapeHub = $.connection.moveShapeHub,
$shape = $("#shape"),
// Send a maximum of 10 messages per second
// (mouse movements trigger a lot of messages)
messageFrequency = 10,
// Determine how often to send messages in
// time to abide by the messageFrequency
updateRate = 1000 / messageFrequency,
shapeModel = {
left: 0,
top: 0
},
moved = false;
moveShapeHub.client.updateShape = function (model) {
shapeModel = model;
// Gradually move the shape towards the new location (interpolate)
// The updateRate is used as the duration because by the time
// we get to the next location we want to be at the "last" location
// We also clear the animation queue so that we start a new
// animation and don't lag behind.
$shape.animate(shapeModel, { duration: updateRate, queue: false });
};
$.connection.hub.start().done(function () {
$shape.draggable({
drag: function () {
shapeModel = $shape.offset();
moved = true;
}
});
// Start the client side server update interval
setInterval(updateServerModel, updateRate);
});
function updateServerModel() {
// Only update server if we have a new movement
if (moved) {
moveShapeHub.server.updateModel(shapeModel);
moved = false;
}
}
});
</script>
<div id="shape" />
</body>
</html>
上面的代码将形状从原来的位置移动到新另一种是由服务器的动画时间间隔 (在这种情况下,100 毫秒),当然。在形状上运行任何前一动画被清除的新动画开始之前。
-
按 f5 键启动该应用程序。复制的页的 URL,并将其粘贴到另一个浏览器窗口。将形状拖在一个浏览器窗口;另一个浏览器窗口中的形状应移动。在另一个窗口形状的运动应出现不生涩,其运动插值在时间,而不是被设置一次每个传入消息。
|