[源码下载]
稳扎稳打Silverlight(23) - 2.0通信之调用WCF的双向通信(Duplex Service)
作者: webabcd
介绍
Silverlight 2.0 调用 WCF 的双向通信服务(Duplex Service) 。开发一个服务端主动向客服端发送股票信息的程序,首先客户端先向服务端发送需要监控的股票的股票代码,然后服务端在该股信息发生变化的时候将信息推送到客户端。
服务端:
定义服务契约及回调接口
从当前上下文获取回调的客户端信道
需要的话则向客户端信道“推”消息
客户端:
构造 PollingDuplexhttpBinding 并在其上创建 IDuplexSessionChannel 的信道工厂
异步方式打开信道工厂
异步方式打开信道
构造需要发送到服务端的消息 System.ServiceModel.Channels.Message
异步向服务端发送消息
监听指定信道,用于异步方式接收服务端返回的消息
不需要再接收服务端的消息则关闭信道
在线DEMO
http://www.cnblogs.com/webabcd/archive/2008/10/09/1307486.html
示例
服务端:
IDuplexService.cs
using System;
using System.Collections.Generic;
using System.linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.Text;
using System.ServiceModel.Channels;
/**/ /// <summary>
/// IDuplexService - 双工(Duplex)服务契约
/// CallbackContract - 双工(Duplex)服务的回调类型
/// </summary>
[ServiceContract(namespace = " Silverlight20 " , CallbackContract = typeof (IDuplexClIEnt))]
public interface IDuplexService
{
/**//// <summary>
/// 客户端向服务端发送消息的方法
/// </summary>
/// <param name="receivedMessage">客户端向服务端发送的消息 System.ServiceModel.Channels.Message</param>
[OperationContract(IsOneWay = true)]
voID SendStockCode(Message receivedMessage);
}
/**/ /// <summary>
/// 双工(Duplex)服务的回调接口
/// </summary>
public interface IDuplexClIEnt
{
/**//// <summary>
/// 客户端接收服务端发送过来的消息的方法
/// </summary>
/// <param name="returnMessage">服务端向客户端发送的消息 System.ServiceModel.Channels.Message</param>
[OperationContract(IsOneWay = true)]
voID ReceiveStockMessage(Message returnMessage);
}
DuplexService.cs
using System;
using System.Collections.Generic;
using System.linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.Text;
using System.ServiceModel.Channels;
using System.Threading;
using System.ServiceModel.Activation;
using System.IO;
/**/ /// <summary>
/// Duplex 服务的服务端的实现
/// 本文以客户端向服务端提交股票代码,服务端定时向客户端发送股票信息为例
/// </summary>
public class DuplexService : IDuplexService
{
IDuplexClIEnt _clIEnt;
bool _status = true;
/**//// <summary>
/// 客户端向服务端发送股票代码的方法
/// </summary>
/// <param name="receivedMessage">包含股票代码的 System.ServiceModel.Channels.Message </param>
public voID SendStockCode(Message receivedMessage)
{
// 获取当前上下文的回调信道
_clIEnt = OperationContext.Current.GetCallbackChannel<IDuplexClIEnt>();
// 如果发生错误则不再执行
OperationContext.Current.Channel.Faulted += new EventHandler(delegate { _status = false; });
// 获取用户提交的股票代码
string stockCode = receivedMessage.Getbody<string>();
// 每3秒向客户端发送一次股票信息
while (_status)
{
// 构造需要发送到客户端的 System.ServiceModel.Channels.Message
// Duplex 服务仅支持 Soap11 , Action 为请求的目的地(需要执行的某行为的路径)
Message stockMessage = Message.CreateMessage(
MessageVersion.soap11,
"Silverlight20/IDuplexService/ReceiveStockMessage",
string.Format("StockCode: {0}; StockPrice: {1}; CurrentTime: {2}",
stockCode,
new Random().Next(1, 200),
DateTime.Now.ToString()));
try
{
// 向客户端“推”数据
_clIEnt.ReceiveStockMessage(stockMessage);
}
catch (Exception ex)
{
// 出错则记日志
using (StreamWriter sw = new StreamWriter(@"C:/Silverlight_Duplex_Log.txt", true))
{
sw.Write(ex.ToString());
sw.Writeline();
}
}
System.Threading.Thread.Sleep(3000);
}
}
}
PollingDuplexServiceHostFactory.cs
using System;
using System.Collections.Generic;
using System.linq;
using System.Web;
using System.ServiceModel;
using System.ServiceModel.Channels;
using System.ServiceModel.Activation;
/**/ /* 以下部分摘自文档 */
// 服务 svc 文件的 Factory 要指定为此类
public class PollingDuplexServiceHostFactory : ServiceHostFactoryBase
{
public overrIDe ServiceHostBase CreateServiceHost(string constructorString,
Uri[] baseAddresses)
{
return new PollingDuplexSimplexServiceHost(baseAddresses);
}
}
class PollingDuplexSimplexServiceHost : ServiceHost
{
public PollingDuplexSimplexServiceHost(params System.Uri[] addresses)
{
base.InitializeDescription(typeof(DuplexService), new UriSchemeKeyedCollection(addresses));
}
protected overrIDe voID InitializeRuntime()
{
// 配置 WCF 服务与 Silverlight 客户端之间的 Duplex 通信
// Silverlight 客户端定期轮询网络层上的服务,并检查回调信道上由服务端发送的所有新的消息
// 该服务会将回调信道上的由服务端发送的所有消息进行排队,并在客户端轮询服务时将这些消息传递到该客户端
PollingDuplexBindingElement pdbe = new PollingDuplexBindingElement()
@H_419_1495@{
// ServerPollTimeout - 轮询超时时间
// InactivityTimeout - 服务端与客户端在此超时时间内无任何消息交换的情况下,服务会关闭其会话
ServerPollTimeout = TimeSpan.FromSeconds(3),
InactivityTimeout = TimeSpan.FromMinutes(1)
};
// 为服务契约(service contract)添加一个终结点(endpoint)
// Duplex 服务仅支持 Soap11
this.AddServiceEndpoint(
typeof(IDuplexService),
new CustomBinding(
pdbe,
new TextMessageEnCodingBindingElement(
MessageVersion.soap11,
System.Text.EnCoding.UTF8),
new httpTransportBindingElement()),
"");
base.InitializeRuntime();
}
}
DuplexService.svc
<% @ ServiceHost Language="C#" DeBUG="true" Service="DuplexService" CodeBehind="~/App_Code/DuplexService.cs" Factory="PollingDuplexServiceHostFactory" %>
客户端:
DuplexService.xaml
< UserControl x:Class ="Silverlight20.Communication.DuplexService"
xmlns ="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x ="http://schemas.microsoft.com/winfx/2006/xaml" >
< StackPanel HorizontalAlignment ="left" margin ="5" >
< TextBox x:name ="txtStockCode" Text ="请输入股票代码" margin ="5" />
< button x:name ="btnsubmit" Content ="获取股票信息" Click ="btnsubmit_Click" margin ="5" />
< button x:name ="btnStop" Content ="停止获取" Click ="btnStop_Click" margin ="5" />
< TextBlock x:name ="lblStockMessage" margin ="5" />
</ StackPanel >
</ UserControl >
DuplexService.xaml.cs
using System;
using System.Collections.Generic;
using System.linq;
using System.Net;
using System.windows;
using System.windows.Controls;
using System.windows.documents;
using System.windows.input;
using System.windows.Media;
using System.windows.Media.Animation;
using System.windows.Shapes;
using System.ServiceModel;
using System.ServiceModel.Channels;
using System.Threading;
using System.IO;
namespace Silverlight20.Communication
{
public partial class DuplexService : UserControl
{
SynchronizationContext _syncContext;
// 是否接收服务端发送过来的消息
bool _status = true;
public DuplexService()
{
InitializeComponent();
}
private voID btnsubmit_Click(object sender, RoutedEventArgs e)
{
_status = true;
// UI 线程
_syncContext = SynchronizationContext.Current;
PollingDuplexhttpBinding binding = new PollingDuplexhttpBinding()
{
// InactivityTimeout - 服务端与客户端在此超时时间内无任何消息交换的情况下,服务会关闭其会话
InactivityTimeout = TimeSpan.FromMinutes(1)
};
// 构造 IDuplexSessionChannel 的信道工厂
IChannelFactory<IDuplexSessionChannel> factory =
binding.BuildChannelFactory<IDuplexSessionChannel>(new BindingParameterCollection());
// 打开信道工厂
IAsyncResult factoryOpenResult =
factory.Beginopen(new AsyncCallback(OnopenCompleteFactory), factory);
if (factoryOpenResult.CompletedSynchronously)
{
// 如果信道工厂被打开的这个 异步 *** 作 已经被 同步完成 则执行下一步
CompleteOpenFactory(factoryOpenResult);
}
}
private voID btnStop_Click(object sender, RoutedEventArgs e)
@H_419_2511@
{_status = false;
}
voID OnopenCompleteFactory(IAsyncResult result)
{
// 该异步 *** 作已被同步完成的话则不做任何 *** 作,反之则执行下一步
if (result.CompletedSynchronously)
return;
else
CompleteOpenFactory(result);
}
voID CompleteOpenFactory(IAsyncResult result)
{
IChannelFactory<IDuplexSessionChannel> factory = result.AsyncState as IChannelFactory<IDuplexSessionChannel>;
// 完成异步 *** 作,以打开信道工厂
factory.EndOpen(result);
// 在信道工厂上根据指定的地址创建信道
IDuplexSessionChannel channel =
factory.CreateChannel(new EndpointAddress("http://localhost:3036/DuplexService.svc"));
// 打开信道
IAsyncResult channelOpenResult =
channel.Beginopen(new AsyncCallback(OnopenCompleteChannel), channel);
if (channelOpenResult.CompletedSynchronously)
{
// 如果信道被打开的这个 异步 *** 作 已经被 同步完成 则执行下一步
CompleteOpenChannel(channelOpenResult);
}
}
voID OnopenCompleteChannel(IAsyncResult result)
{
// 该异步 *** 作已被同步完成的话则不做任何 *** 作,反之则执行下一步
if (result.CompletedSynchronously)
return;
else
CompleteOpenChannel(result);
}
voID CompleteOpenChannel(IAsyncResult result)
{
IDuplexSessionChannel channel = result.AsyncState as IDuplexSessionChannel;
// 完成异步 *** 作,以打开信道
channel.EndOpen(result);
// 构造需要发送到服务端的 System.ServiceModel.Channels.Message (客户端终结点与服务端终结点之间的通信单元)
Message message = Message.CreateMessage(
channel.GetProperty<MessageVersion>(), // MessageVersion.soap11 (Duplex 服务仅支持 Soap11)
"Silverlight20/IDuplexService/SendStockCode", // Action 为请求的目的地(需要执行的某行为的路径)
txtStockCode.Text);
// 向目的地发送消息
IAsyncResult resultChannel =
channel.BeginSend(message, new AsyncCallback(OnSend), channel);
if (resultChannel.CompletedSynchronously)
{
// 如果向目的地发送消息的这个 异步 *** 作 已经被 同步完成 则执行下一步
CompleteOnSend(resultChannel);
}
// 监听指定的信道,用于接收返回的消息
ReceiveLoop(channel);
}
voID OnSend(IAsyncResult result)
{
// 该异步 *** 作已被同步完成的话则不做任何 *** 作,反之则执行下一步
if (result.CompletedSynchronously)
return;
else
CompleteOnSend(result);
}
voID CompleteOnSend(IAsyncResult result)
{
try
{
IDuplexSessionChannel channel = (IDuplexSessionChannel)result.AsyncState;
// 完成异步 *** 作,以完成向目的地发送消息的 *** 作
channel.EndSend(result);
}
catch (Exception ex)
{
_syncContext.Post(WriteText, ex.ToString() + Environment.Newline);
}
}
voID ReceiveLoop(IDuplexSessionChannel channel)
{
// 监听指定的信道,用于接收返回的消息
IAsyncResult result =
channel.BeginReceive(new AsyncCallback(OnReceiveComplete), channel);
if (result.CompletedSynchronously)
@H_61_3404@
{CompleteReceive(result);
}
}
voID OnReceiveComplete(IAsyncResult result)
{
if (result.CompletedSynchronously)
return;
else
CompleteReceive(result);
}
voID CompleteReceive(IAsyncResult result)
{
IDuplexSessionChannel channel = (IDuplexSessionChannel)result.AsyncState;
try
{
// 完成异步 *** 作,以接收到服务端发过来的消息
Message receivedMessage = channel.EndReceive(result);
if (receivedMessage == null)
{
// 服务端会话已被关闭
// 此时应该关闭客户端会话,或向服务端发送消息以启动一个新的会话
}
else
{
// 将接收到的信息输出到界面上
string text = receivedMessage.Getbody<string>();
_syncContext.Post(WriteText, text + Environment.Newline);
if (!_status)
{
// 关闭信道
IAsyncResult resultFactory =
channel.BeginClose(new AsyncCallback(OnCloseChannel), channel);
if (resultFactory.CompletedSynchronously)
{
CompleteCloseChannel(result);
}
}
else
{
// 继续监听指定的信道,用于接收返回的消息
ReceiveLoop(channel);
}
}
}
catch (Exception ex)
{
// 出错则记日志
using (StreamWriter sw = new StreamWriter(@"C:/Silverlight_Duplex_Log.txt", true))
{
sw.Write(ex.ToString());
sw.Writeline();
}
}
}
voID OnCloseChannel(IAsyncResult result)
{
if (result.CompletedSynchronously)
return;
else
CompleteCloseChannel(result);
}
voID CompleteCloseChannel(IAsyncResult result)
{
IDuplexSessionChannel channel = (IDuplexSessionChannel)result.AsyncState;
// 完成异步 *** 作,以关闭信道
channel.EndClose(result);
}
voID WriteText(object text)
{
// 将信息打到界面上
lblStockMessage.Text += (string)text;
}
}
}
OK
[源码下载] 总结
以上是内存溢出为你收集整理的稳扎稳打Silverlight(23) - 2.0通信之调用WCF的双向通信(Duplex Service)全部内容,希望文章能够帮你解决稳扎稳打Silverlight(23) - 2.0通信之调用WCF的双向通信(Duplex Service)所遇到的程序开发问题。
如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)