原文:[SignalR]SignalR与WCF双工模式结合实现服务端数据直推浏览器端

之前开发基于WinForm监控的软件,服务端基于Wcf实现,里面涉及双工模式,在客户端里面,采用心跳包机制保持与服务端链接,现在有了新需求,需要开发网页版形式,所以怎么保持与服务端链接是重要点,由于数据量比较大,所以不能采用客户端发起请求不断轮询的方式。参考各种资料后,使用SignalR,主要是支持WebSockets通信。并且Hub链接方式解决了realtime 信息交换的功能问题。

下图是MSDN关于解释:

Hub:提供与连接到 Hub 的 SignalR 连接进行通信的方法。

Global.asax

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Security;
using System.Web.SessionState;
using System.Web.Routing;
using Microsoft.AspNet.SignalR;
namespace LMSCitySignalR
{
public class Global : System.Web.HttpApplication
{ protected void Application_Start(object sender, EventArgs e)
{
RouteTable.Routes.MapHubs();
} protected void Session_Start(object sender, EventArgs e)
{ } protected void Application_BeginRequest(object sender, EventArgs e)
{ } protected void Application_AuthenticateRequest(object sender, EventArgs e)
{ } protected void Application_Error(object sender, EventArgs e)
{ } protected void Session_End(object sender, EventArgs e)
{ } protected void Application_End(object sender, EventArgs e)
{ }
}
}

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

页面代码:

<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="CityLmsClient.aspx.cs" Inherits="LMSCitySignalR.CityLmsClient" %>

<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"> <head runat="server">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>LH CityLMS Client</title>
</head>
<body>
<div id="dvMsg"></div>
Client Mac Address:
<input id="txtMac" type="text" value="50:E5:49:DA:4C:D6" />
<input id="btnCnLmsSvr" type="button" value="Connect CityLms Server" />
<br>
User Name:<input id="txtUserName" type="text" value="admin" />
User Password:<input id="txtUserPassword" type="password" value="admin" />
<input id="btnLogin" type="button" value="Login" />
<br> <input id="btnMonitorClientChanel" type="button" value="MonitorClientChanel" />
<br />
<input id="btnEmergencyControl" type="button" value="Emergency Control" />
<br />
<input id="btnDisConSvr" type="button" value="DisConnect Svr" />
<script src="Scripts/jquery-1.6.4.js" type="text/javascript"></script>
<script src="Scripts/json2.js" type="text/javascript"></script>
<script src="Scripts/jquery.signalR-1.1.1.js" type="text/javascript"></script> <script src="/signalr/hubs" type="text/javascript"></script>
<script type="text/javascript">
$(function () { /*
* 参考链接:http://www.cnblogs.com/shanyou/archive/2012/07/28/2613693.html
*· Persistent Connection(HTTP持久链接):持久性连接,用来解决长时间连接的能力,而且还可以由客户端主动向服务器要求数据,而服务器端也不需要实现太多细节,只需要处理 PersistentConnection 内所提供的五个事件:OnConnected, OnReconnected, OnReceived, OnError 和 OnDisconnect 即可。
*· Hub:信息交换器,用来解决 realtime 信息交换的功能,服务器端可以利用 URL 来注册一个或多个 Hub,只要连接到这个 Hub,就能与所有的客户端共享发送到服务器上的信息,同时服务器端可以调用客户端的脚本,不过它背后还是不离 HTTP 的标准,所以它看起来神奇,但它并没有那么神奇,只是 JavaScript 更强,强到可以用像 eval() 或是动态解释执行的方式,允许 JavaScript 能够动态的加载与执行方法调用而己。
*/
/*链接对应server端Hub对象*/
var cityLmsClient = $.connection.cityLmsClientHub;
cityLmsClient.client.cntServerResult = function (name, message) {
$('#dvMsg').append('<li><strong>' + (new Date()).toLocaleTimeString() + '-Client Mac Address:' + name
+ ',&nbsp;&nbsp; Connect CityLms Server Result:' + message + '</strong></li>');
};
/*断开连接消息提示*/
cityLmsClient.client.disConSvr = function (message) {
alert(message);
};
/*操作消息提示*/
cityLmsClient.client.operateMsg = function (message) {
$('#dvMsg').append('<li><strong>' + (new Date()).toLocaleTimeString() + '-' + message + '</strong></li>');
}; $.connection.hub.start().done(function () { /*链接wcf Server*/
$("#btnCnLmsSvr").click(function () {
cityLmsClient.server.conServer($("#txtMac").val());
}); /*应急操作*/
$("#btnEmergencyControl").click(function () {
cityLmsClient.server.emergencyControl();
});
/*用户登录*/
$("#btnLogin").click(function () {
cityLmsClient.server.userLogin($("#txtUserName").val(), $("#txtUserPassword").val());
});
/*启动心跳包,以保持与wcf Server连接*/
$("#btnMonitorClientChanel").click(function () {
cityLmsClient.server.monitorClientChanel();
});
/*断开连接*/
$("#btnDisConSvr").click(function () {
cityLmsClient.server.disConnectSvr();
});
});
/*日志显示*/
$.connection.hub.logging = true; }); </script> </body>
</html>

cityLmsClientHub.cs代码
.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.ServiceModel;
using System.Threading;
using System.Web;
using DL_LMS_Server.Default.Shared;
using DL_LMS_Server.Service.DataModel.Parameter;
using DL_LMS_Server.Service.DataModel.Result;
using Microsoft.AspNet.SignalR; namespace LMSCitySignalR
{
public class cityLmsClientHub : Hub
{
ServiceCallBack serCallBack = null;
/// <summary>
/// 应急操作回调
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void RealTimeCabChCallBackMessage_Event(object sender, LMSClientNotifiedEventArgs e)
{
COptRealTimeCabChResult optCabChresult = e.NotifiedMessage as COptRealTimeCabChResult;
string _sMsg = string.Format("{0}-CabID:{1},byCh1ActType:{2},byCh2ActType:{3},byCh3ActType:{4},byCh4ActType:{5},byCh5ActType:{5},byCh6ActType:{6},CtuLockStatus:{7}",
DateTime.Now.ToShortTimeString(),
optCabChresult.CabID,
optCabChresult.byCh1ActType,
optCabChresult.byCh2ActType,
optCabChresult.byCh3ActType,
optCabChresult.byCh4ActType,
optCabChresult.byCh5ActType,
optCabChresult.byCh6ActType,
optCabChresult.CtuLockStatus);
Clients.Client(Context.ConnectionId).OperateMsg(_sMsg);
Clients.Client(Context.ConnectionId).OperateMsg("==========================end======================");
}
public void Hello()
{
Clients.All.hello();
}
private static bool bIsConnect = false;
private static string sMacAddress = null;
private static string sUserName = null;
private static string sUserPassword = null;
/// <summary>
///链接wcf Server
/// </summary>
/// <param name="clientMacAddress">mac地址</param>
/// <returns></returns>
private CommunResult ConnService(string clientMacAddress)
{
CommunResult result = new CommunResult();
try
{
SvrRetMessage svrMessage = ClientComServiceFactory.GetClientServiceFactory.GetClientComService.Connect(clientMacAddress);
if (!svrMessage.ExcuResult)
{
result.Message = svrMessage.Message;
result.CommunState = CommState.NoRegister;
}
result.CommunState = CommState.Scuess;
result.Message = "连接成功"; }
catch (EndpointNotFoundException e)
{
string mes = e.Message;
result.CommunState = CommState.Failed;
result.Message = CommMessage.sNoServer;
}
catch (TimeoutException e)
{
string mes = e.Message;
result.CommunState = CommState.TimeOut;
result.Message = CommMessage.sTimeOuteMessahe;
}
catch (Exception e)
{
string mes = e.Message;
result.CommunState = CommState.Failed;
result.Message = CommMessage.sNoServer;
}
return result;
}
/// <summary>
/// 断开与wcf Server链接
/// </summary>
public void DisConnectSvr()
{
string _sDisConSvrMsg = string.Format("{0}{1}.", sMacAddress, DisConnService().Message);
Clients.Client(Context.ConnectionId).DisConSvr(_sDisConSvrMsg);
Debug.Write(_sDisConSvrMsg);
}
/// <summary>
/// 客户端与服务器端断开连接
/// </summary>
/// <returns></returns>
private CommunResult DisConnService()
{
CommunResult result = new CommunResult();
try
{
ClientComServiceFactory.GetClientServiceFactory.GetClientComService.DisConnect(sMacAddress);
result.CommunState = CommState.Scuess;
result.Message = "断开连接成功";
}
catch (EndpointNotFoundException e)
{
string mes = e.Message;
result.CommunState = CommState.Failed;
result.Message = CommMessage.sNoServer;
}
catch (TimeoutException e)
{
string mes = e.Message;
result.CommunState = CommState.TimeOut;
result.Message = CommMessage.sTimeOuteMessahe;
}
catch (Exception e)
{
string mes = e.Message;
result.CommunState = CommState.Failed;
result.Message = CommMessage.sNoServer; }
return result;
}
/// <summary>
/// 心跳包,保持与wcf server链接
/// </summary>
public void MonitorClientChanel()
{
if (string.IsNullOrEmpty(sUserPassword) || string.IsNullOrEmpty(sUserName))
return;
ThreadPool.QueueUserWorkItem
(
delegate
{ while (true)
{
Thread.Sleep(5000);
try
{
Debug.WriteLine(string.Format("{1}-Client ID:{0}", Context.ConnectionId, DateTime.Now));
if (ClientComServiceFactory.GetClientServiceFactory.getObjetcStatus.State == CommunicationState.Faulted)
{
ClientComServiceFactory.GetClientServiceFactory.getObjetcStatus.Abort();
ClientComServiceFactory.GetClientServiceFactory.GetNewClientComService();
} ClientComServiceFactory.GetClientServiceFactory.GetClientComService.ReConnect(sMacAddress, sUserName, sUserPassword); }
catch (Exception ex)
{ ClientComServiceFactory.GetClientServiceFactory.GetNewClientComService();
Debug.WriteLine(string.Format("Time:{0}-Exception:{1}-Type:{2}", DateTime.Now.ToString("HH:mm:ss"), ex.Message.ToString(), this.GetType().ToString()));
}
} }
); }
/// <summary>
/// 链接wcf Server
/// </summary>
/// <param name="clientMacAddress">Mac地址</param>
public void ConServer(string clientMacAddress)
{
//DebugerHelper dHelper = new DebugerHelper(DebugParameter.ObtainCalledMethod);
//dHelper.FormartDebuger("Test");
CommunResult _comStatus = ConnService(clientMacAddress);
//FormartDebuger(MethodBase.GetCurrentMethod(), "hello");
Clients.Client(Context.ConnectionId).CntServerResult(clientMacAddress, _comStatus.Message);
if (_comStatus.CommunState == CommState.Scuess)
{
sMacAddress = clientMacAddress;
bIsConnect = true;
}
}
/// <summary>
/// 用户登录
/// </summary>
/// <param name="sName">用户名称</param>
/// <param name="sPassWord">用户密码</param>
public void UserLogin(string sName, string sPassWord)
{
if (CheckConnectStatus())
{
LoginResult _serverLoginResult = ClientComServiceFactory.GetClientServiceFactory.GetClientComService.UserLogin(sMacAddress, sName, sPassWord);
if (_serverLoginResult.UserLoginStatus == LoginStatus.scuess)
{
sUserName = sName;
sUserPassword = sPassWord;
ServiceCallBack.RealTimeCabChCallBack += RealTimeCabChCallBackMessage_Event;
}
Clients.Client(Context.ConnectionId).OperateMsg(string.Format("用户:{0},登录:{1}。", sName, _serverLoginResult.UserLoginStatus == LoginStatus.scuess ? "成功" : "失败,原因:" + _serverLoginResult.LoginMessage));
}
}
/// <summary>
/// 应急操作
/// </summary>
public void EmergencyControl()
{
if (CheckConnectStatus())
{
OptRealCtuChannelParameter parameter = new OptRealCtuChannelParameter();
parameter.byCh1ActType = 1;
parameter.byCh2ActType = 1;
parameter.byCh3ActType = 1;
parameter.byCh4ActType = 1;
parameter.byCh5ActType = 1;
parameter.byCh6ActType = 1;
parameter.CabID = "640afa41-b3c6-4c77-bf1b-cf2c4977fbfa";
parameter.ClientMacAddress = sMacAddress;
parameter.OptTimeOut = 10000;
parameter.OptRealDateTime = DateTime.Now;
parameter.RealTimeStatus = 63;
SvrRetMessage returnMessage = ClientComServiceFactory.GetClientServiceFactory.GetClientComService.SendOptRealTimeCtuChMessage(parameter, sMacAddress);
Clients.Client(Context.ConnectionId).OperateMsg(string.Format("CabID:{0},应急控制,操作:{1}。", parameter.CabID, returnMessage.ExcuResult == true ? "成功" : "失败,原因:" + returnMessage.Message));
}
}
/// <summary>
/// 检查是否已经连接wcf Server
/// </summary>
/// <returns></returns>
private bool CheckConnectStatus()
{
if (bIsConnect && !string.IsNullOrEmpty(sMacAddress))
return true;
else
Clients.Client(Context.ConnectionId).OperateMsg("当前还未连接CityLms Server.");
return false;
} }
}

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

实现效果

才疏学浅,如有错误,敬请指出。

[SignalR]SignalR与WCF双工模式结合实现服务端数据直推浏览器端的更多相关文章

  1. 利用WCF双工模式实现即时通讯

    概述 WCF陆陆续续也用过多次,但每次都是浅尝辄止,以将够解决问题为王道,这几天稍闲,特寻了些资料看,昨晚尝试使用WCF的双工模式实现了一个简单的即时通讯程序,通过服务端转发实现客户端之间的通讯.这只 ...

  2. WCF 双工模式

    WCF之消息模式分为:1.请求/答复模式2.单向模式3.双工模式 其中,请求/答复模式,在博文: WCF 入门教程一(动手新建第一个WCF程序并部署) WCF 入门教程二 中进行了详细介绍,此处将主要 ...

  3. WCF双工通讯以及客户端间的间接通讯

    由于学习计划安排不当,对WCF的认知一直停滞不前,最近工作上又用回了WCF,重拾一下,看到蒋老师介绍双工通讯的博文,实践一下,积累一下.原想着WCF的双工通讯就是原本的客户端能调用服务端的方法之余,服 ...

  4. WCF双工学习笔记

    WCF双工的作用在于服务端执行某个方法的时候调用客户端的方法,有点类似委托的感觉,实际项目中在什么情况下使用还没想到. WCF双工支持两种bind,一是nettcp.另一个是wsDualHttp,这里 ...

  5. WCF学习之旅—TCP双工模式(二十一)

    WCF学习之旅—请求与答复模式和单向模式(十九) WCF学习之旅—HTTP双工模式(二十) 五.TCP双工模式 上一篇文章中我们学习了HTTP的双工模式,我们今天就学习一下TCP的双工模式. 在一个基 ...

  6. WCF学习之旅—HTTP双工模式(二十)

    WCF学习之旅—请求与答复模式和单向模式(十九) 四.HTTP双工模式 双工模式建立在上文所实现的两种模式的基础之上,实现客户端与服务端相互调用:前面介绍的两种方法只是在客户端调用服务端的方法,然后服 ...

  7. WCF服务创建与使用(双工模式)

    昨天发布了<WCF服务创建与使用(请求应答模式)>,今天继续学习与强化在双工模式下WCF服务创建与使用,步骤与代码如下. 第一步,定义服务契约(Service Contract),注意Se ...

  8. 使用wcf的双工模式做的一个控制台聊天app

    //wcf 服务 using System; using System.Collections.Generic; using System.Linq; using System.Runtime.Ser ...

  9. WCF入门教程3——WCF通信模式

    本章内容 请求/响应模式 单工模式 双工模式 WCF异步调用 请求与响应模式 请求/响应     请求/响应通信是指客户端向服务端发送消息后,服务端会向客户端发送响应.这也意味着在接收到服务的响应以前 ...

随机推荐

  1. ORACLE存储过程创建失败,如何查看其原因

    工作中用SQL Server比较多,Oracle可以说是小白,最近想用存储过程来完成单据复制的功能,结果遇到各种问题,其实都是非常简单的问题,但是对我来说还是花了很多时间来解决,浪费这些时间非常不值得 ...

  2. win7+vs2010+opencv2.4.6配置

    记录一下配置,省的以后还到处去找: (一) 添加环境变量://第一次使用opencv的话需要加环境变量:” %opencv%\build\x86\vc10\bin”和”%opencv%\build\c ...

  3. 搭建maven环境

    有两种方式可以配置maven的环境配置,本人推荐使用第二种,即使用本地的maven安装文件,个人感觉这样可以方便管理下载jar包的存放位置,错误信息的输出等,可以在dos窗口中可以清晰看到,虽然比较麻 ...

  4. python第三方库学习(2):requests

    Make a Request r = requests.get('https://github.com/timeline.json') Passing Parameters In URLspayloa ...

  5. sharedpreferences的简单使用

    sharedpreferences 以键值对的方式将数据保存在xml   创建:SharePreferences sp = getShareferences(name,context.---) con ...

  6. 【转】25个必须记住的SSH命令

    1.复制SSH密钥到目标主机,开启无密码SSH登录 ssh-copy-id user@host 如果还没有密钥,请使用ssh-keygen命令生成. 2.从某主机的80端口开启到本地主机2001端口的 ...

  7. 堆排序Heap sort

    堆排序有点小复杂,分成三块 第一块,什么是堆,什么是最大堆 第二块,怎么将堆调整为最大堆,这部分是重点 第三块,堆排序介绍 第一块,什么是堆,什么是最大堆 什么是堆 这里的堆(二叉堆),指得不是堆栈的 ...

  8. Android Studio--Gradle基础(转)

    原文链接:http://stormzhang.com/devtools/2014/12/18/android-studio-tutorial4/ 其实很早之前也写了一篇Gradle的基础博客,但是时间 ...

  9. JS-JQuery(JSONP)调用WebService跨域若干技术点

    1.JSONP:JSON With Padding,让网页从别的网域获取信息,也就是跨域获取信息,可以当做是一种“工具”,大多数架构Jquery.EXTjs等都支持. 由于同源策略,一般来说位于 se ...

  10. 置入式模型inclusion model和显示具现化

    1.置入式模型 链接错误: 大多数非模板程序代码的组织如下:A,类声明在头文件中: B:全局变量和非inline函数在cpp文件中定义 但是,如果模板程序也这样组织,则会出错.原因在于:函数模板的定义 ...