博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
WCF 第二章 契约 实现一个双向契约的服务端部分
阅读量:7014 次
发布时间:2019-06-28

本文共 4248 字,大约阅读时间需要 14 分钟。

一个双向契约包含服务终结点和客户端终结点的接口实现。在契约类型中,服务端契约在客户端实现。

列表2.6为一个提供stock price更新的服务定义一个服务契约。它使用双工通信以便于一个客户端可以注册更新,服务将周期性的发送更新消息给客户端。客户端通过调用服务端的 RegisterForUpdates操作来初始化通信。服务然后会创建一个线程来周期性的通过调用客户端的PriceUpdate操作来发送更新消息。

列表2.6 双工服务契约:服务端实现

 
using
System;
using
System.Collections.Generic;
using
System.Linq;
using
System.Text;
using
System.ServiceModel;
namespace
Contract
{
[ServiceContract(CallbackContract
=
typeof
(IClientCallback))]
public
interface
IServerStock
{
[OperationContract(IsOneWay
=
true
)]
void
RegisterForUpdates(
string
ticker);
}
public
interface
IClientCallback
{
[OperationContract(IsOneWay
=
true
)]
void
PriceUpdate(
string
ticker,
double
price);
}
public
class
ServerStock : IServerStock
{
//
This is NOT a good notification algorithm as it's creating
//
one thread per client. It should be inverted so it's creating
//
one thread per ticker instead.
public
void
RegisterForUpdates(
string
ticker)
{
Update bgWorker
=
new
Update();
bgWorker.callback
=
OperationContext.Current.GetCallbackChannel
<
IClientCallback
>
();
Thread t
=
new
Thread(
new
ThreadStart(bgWorker.SendUpdateToClient));
t.IsBackground
=
true
;
t.Start();
}
}
public
class
Update
{
public
IClientCallback callback
=
null
;
public
void
SendUpdateToClient()
{
Random p
=
new
Random();
for
(
int
i
=
0
; i
<
10
; i
++
)
{
Thread.Sleep(
5000
);
//
updates occurs somewhere
try
{
callback.PriceUpdate(
"
msft
"
,
100.00
+
p.NextDouble());
}
catch
(Exception ex)
{
Console.WriteLine(
"
Error sendinig cache to client:{0}
"
, ex.Message);
}
}
}
}
}

为了完整性,相关配置文件在列表2.7中显示。注意这里使用了双向绑定。

列表2.7 双工服务契约:服务端配置

 
<?
xml version="1.0" encoding="utf-8"
?>
<
configuration
>
<
system.serviceModel
>
<
services
>
<
service
behaviorConfiguration
="MEXServiceTypeBehaviro"
name
="EssentialWCF.StockService"
>
<
endpoint
address
=""
binding
="wsDualHttpBinding"
contract
="EssentialWCF.IStockService"
/>
<
endpoint
address
="mex"
binding
="mexHttpBinding"
contract
="IMetadataExchange"
/>
</
service
>
</
services
>
<
behaviors
>
<
serviceBehaviors
>
<
behavior
name
="MEXServiceTypeBehaviro"
>
<
serviceMetadata
httpGetEnabled
="true"
/>
</
behavior
>
</
serviceBehaviors
>
</
behaviors
>
</
system.serviceModel
>
</
configuration
>

列表2.6中的代码有一个问题:它为每个客户端创建一个线程。对这个情况来说,可能有不可预测的客户端数目(可能是上百万个),但是stock tickers是有限的(以千记)。因此,为每个stock ticke创建一个线程比为每个客户端创建一个线程会更好。

  列表2.8显示了另一种方法。在这个例子中,使用一个哈希表来维护并跟踪每个客户端请求更新的stock tickers.Update 类存储在哈希表中而且每个Update类在自己的线程上执行。客户端回调列表存储在Update类的本地线程存储区中,所以Update类可以通知所有的 客户端关于一个特殊的stock ticker可用。注意当访问客户端列表集合时会设置一个锁,在主StockService类中的RegisterForUpdates方法和 Update类本身都有锁。当列表集合被Update类修改时保证列表同时不会被StockeService类更新是必要的。

列表2.8 双工服务契约:服务端实现(更好的线程利用)

 
public
class
ServerStock : IServerStock
{
public
class
Worker
{
public
string
ticker;
public
Update workerProcess;
}
public
static
Hashtable workers
=
new
Hashtable();
public
void
RegisterForUpdates(
string
ticker)
{
Worker w
=
null
;
//
if needed, create a new worker, add it to the hashtable
//
and start it on a new thread
if
(
!
workers.ContainsKey(ticker))
{
w
=
new
Worker();
w.ticker
=
ticker;
w.workerProcess
=
new
Update();
w.workerProcess.ticker
=
ticker;
workers[ticker]
=
w;
Thread t
=
new
Thread(
new
ThreadStart(w.workerProcess.SendUpdateToClient));
t.IsBackground
=
true
;
t.Start();
}
}
}
public
class
Update
{
public
string
ticker;
public
List
<
IClientCallback
>
callbacks
=
new
List
<
IClientCallback
>
();
public
void
SendUpdateToClient()
{
Random w
=
new
Random();
Random p
=
new
Random();
while
(
true
)
{
Thread.Sleep(w.Next(
5000
));
//
updates occurs somewhere
lock
(callbacks)
{
foreach
(IClientCallback c
in
callbacks)
{
try
{
c.PriceUpdate(ticker,
100.00
+
p.NextDouble()
*
10
);
}
catch
(Exception ex)
{
Console.WriteLine(
"
Error sendinig cache to client:{0}
"
, ex.Message);
}
}
}
}
}
}
  

  对于在列表2.7中显示的每客户端一个线程的实现或者列表2.8中显示的每个ticker一个线程的实现方式来说,仍然有可靠性问题。比如,如果服务的不 能调用客户端的回调方法,它打印一条日志到控制台,但是它从不会重试。服务端应该重试吗?如果是的话,多久重试一次?什么时候应该停止呢?或者,客户端知 道有一个窗口期,在这个期间它将不会接收到更新消息,那么客户端应该从哪里查询更新以便于在接下来的时间可以继续查询?有很多需要解决的重要问题,通过使 用代理,比如微软BizTalk服务或者其他类似产品可以解决。消息代理一般有持久的存储介质(数据库,文件系统或者消息队列)在核心系统上而且包括鲁棒 性配置工具来确定传输和重试协议。但是它们也要承担性能,复杂度和费用的开销,所以解决方案将很大程度上依赖需求。

========

转载自

作者:
出处:
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
 

转载于:https://www.cnblogs.com/llbofchina/archive/2011/06/27/2091359.html

你可能感兴趣的文章
运行.bat批处理,CMD窗口隐藏,并制作为EXE文件
查看>>
zoj 1642 Match for Bonus(动态规划)
查看>>
20130414_怎样让博客园首页只显示文章标题与摘要
查看>>
关于LittleSis网站数据API的简单整理
查看>>
[转]提升6种心理商数 多角度展现个人魅力
查看>>
HDU 1893 Sibonacci Numbers(斐波那契)
查看>>
tempdb相关文章
查看>>
带包头路由协议的创建过程(转帖)
查看>>
Android 左右滑屏效果
查看>>
类方法代码重构-寻找坏味道
查看>>
析构函数构造函数CPerson派生出CEmployee类
查看>>
安装文件在Ubuntu12.04上部署CloudFoundry-ng (一) dea_ng和warden的部署
查看>>
SkinSharp For C# .Net 2005/2008/2010 使用帮助
查看>>
华夏工程dom4j (2) 编辑
查看>>
Metro Studio 2.0.1.5
查看>>
MSSQL有关时间函数知识(转)
查看>>
Windows Phone 更改datePicker的显示格式
查看>>
JSP和JSTL获取服务器参数
查看>>
lxml.etree 教程5:Using XPath to find text
查看>>
Python学习入门基础教程(learning Python)--2.2 Python下的变量基础
查看>>