Silverlight与WCF之间的通信(2)利用WCF的双工通信“推送”给SL数据

Silverlight与WCF之间的通信(2)利用WCF的双工通信“推送”给SL数据,第1张

概述一,Duplex简介 上一个随笔记录了SL利用Timer定时去WCF上取数据再绑定到界面上的问题,今天尝试用了WCF的Duplex双工通信来做这个事情,也以这个例子来说明WCF中Duplex的使用。 双工通信的原理很简单,我们平时用的是客户端调用服务端的方法来获取数据,而Duplex是将客户端也当作了服务器,客户端上的方法也可以被调用,以聊天功能为例子,用户A连接到服务器后,之前的做法是客户端定时 一,Duplex简介

上一个随笔记录了SL利用Timer定时去WCF上取数据再绑定到界面上的问题,今天尝试用了WCF的Duplex双工通信来做这个事情,也以这个例子来说明WCF中Duplex的使用。

双工通信的原理很简单,我们平时用的是客户端调用服务端的方法来获取数据,而Duplex是将客户端也当作了服务器,客户端上的方法也可以被调用,以聊天功能为例子,用户A连接到服务器后,之前的做法是客户端定时取数据,而Duplex是在服务端定时检测数据变化,如果发现了发送给A的信息,那么立即会调用客户端的方法来推送信息到A。

二,建立Duplex模式的WCF服务

这里以一个简单的聊天功能来说明,WCF提供了三个方法,连接到服务器方法,发送信息方法和接收信息方法。从服务契约上来说分为两个接口,分别是为客户端提供发送信息和开始聊天方法的IChatService接口和服务器调用客户端方法的IChatServiceCallBack接口

IChatService.cs文件

代码 namespace ChatWCF
{
[ServiceContract(CallbackContract
= typeof (IChatServiceCallBack))] // 这里需要定义IChatService接口的回调接口IChatServiceCallBack
public interface IChatService
{
[OperationContract]
bool SendMessage(MessageInfo msg); // 发送信息

[OperationContract]
bool LoginChat( string User, string Partner); // 开始聊天模式
}

[ServiceContract]
public interface IChatServiceCallBack //供 服务端回调的接口
{
[OperationContract(IsOneWay
= true )]
voID ReceiveMessages(List < MessageInfo > ListMessages); // 客户端被服务端回调后接收信息
}
}

 

接下来需要实现这接口,IChatService.svc.cs

 

代码 namespace ChatWCF
{
public class ChatService : IChatService
{
IChatServiceCallBack chatserviceCallBack;
string _user;
string _partner;
     Timer timer;
// 开始聊天
public bool LoginChat( string User, string Partner)

{
try
{
chatserviceCallBack
= OperationContext.Current.GetCallbackChannel < IChatServiceCallBack > ();
_user
= User;
_partner
= Partner;

timer
= new Timer( new TimerCallback(CheckMessages), this , 100 , 100 );

return true ;
}
catch (Exception ex)
{
return false ;
}
}
//检查消息并回调客户端接收此消息,此处是回调的重点
private voID CheckMessages( object o) {
chatserviceCallBack.ReceiveMessages(GetMessages(_user,_partner));
}

// 发送信息
public bool SendMessage(MessageInfo msg)
{

[
将MessageInfo写入数据库...]
}

// 检测数据库
private List < MessageInfo > GetMessages( string User, string Partner)
{
List
< MessageInfo > ListMsg = new List < MessageInfo > ();
[检测数据库并返回检测到的MessageInfo...]  
return ListMsg;
}

// 执行简单的SQL语句
private DataSet Excutesql( string strsql)
{
string strServer = " server=LEON-PC\sql2005;database=jplan;uID=sa;pwd=sa; " ;
sqlConnection con
= new sqlConnection(strServer);
con.open();
sqlDataAdapter dataAdapter
= new sqlDataAdapter(strsql,con);
DataSet ds
= new DataSet();
dataAdapter.Fill(ds);
con.Close();

return ds;
}
}
}

 

这里需要注意一点的是这个WCF是建立在Duplex基础上的,所以在wcf的项目中需要添加一个程序集:

Assembly System.ServiceModel.PollingDuplex
C:\Program files\Microsoft SDKs\Silverlight\v4.0\librarIEs\Server\System.ServiceModel.PollingDuplex.dll

 

接下来需要对Web.config进行配置,主要是ServiceModel节点:

代码 < system.serviceModel >
< behaviors >
< serviceBehaviors >
< behavior name ="ChatWCF.ChatBehavior" >
< serviceMetadata httpGetEnabled ="true" />
< serviceDeBUG includeExceptionDetailinFaults ="false" />
</ behavior >
</ serviceBehaviors >
</ behaviors >
< services >
< service behaviorConfiguration ="ChatWCF.ChatBehavior" name ="ChatWCF.ChatService" >
< endpoint
address =""
binding
="pollingDuplexhttpBinding"
bindingConfiguration
="multipleMessagesPerPollPollingDuplexhttpBinding"
contract
="ChatWCF.IChatService" >
</ endpoint >
< endpoint
address ="mex"
binding
="mexhttpBinding"
contract
="IMetadataExchange" />
</ service >
</ services >
< extensions >
< bindingExtensions >
< add name =
"pollingDuplexhttpBinding"

type
="System.ServiceModel.Configuration.PollingDuplexhttpBindingCollectionElement,System.ServiceModel.PollingDuplex,Version=4.0.0.0,Culture=neutral,PublicKeyToken=31bf3856ad364e35" />
</ bindingExtensions >
</ extensions >

< bindings >
< pollingDuplexhttpBinding >
< binding name ="multipleMessagesPerPollPollingDuplexhttpBinding"
duplexMode
="MultipleMessagesPerPoll"
maxOutputDelay
="00:00:07" />
</ pollingDuplexhttpBinding >
</ bindings >
< serviceHostingEnvironment multipleSiteBindingsEnabled ="true" />
</ system.serviceModel >

 

如果您的WCF服务是一个单独的站点,而客户端是SL的话,鉴于SL的安全性考虑不支持跨域访问,那么就需要在WCF的根目录下放置一个XML策略文件,文件名为

clIEntaccesspolicy.xml:

代码 <? xml version="1.0" enCoding="utf-8" ?>
< access-policy >
< cross-domain-access >
< policy >
< allow-from http-request-headers ="SOAPAction" >
< domain uri ="*" />
</ allow-from >
< grant-to >
< resource path ="/" include-subpaths ="true" />
</ grant-to >
</ policy >
</ cross-domain-access >
</ access-policy >

 

如果您的配置和代码书写正确,浏览一下WCF服务会发现下图,说明服务已经正确host到VS的轻量级IIS上了

三,Silverlight跨域访问WCF的Duplex服务

先建立一个单独的project,silverlight app,当然还是需要先引用WCF服务的:

新建一个SL文件,Chat.xaml代码,包括了一个发送消息窗口和一个显示聊天信息的窗口,这个聊天的窗口从普通HTML街面上接收两个参数,即user和partner互为聊天对象。

代码 < UserControl x:Class ="ChatSL.Chat"
xmlns
="http://schemas.microsoft.com/winfx/2006/xaml/presentation%22
xmlns:x="
http://schemas.microsoft.com/winfx/2006/xaml%22
xmlns:d
="http://schemas.microsoft.com/Expression/blend/2008%22
xmlns:mc="
http://schemas.openxmlformats.org/markup-compatibility/2006%22
mc:Ignorable
="d"
d:DesignHeight
="510" d:DesignWIDth ="514" >

< GrID x:name ="LayoutRoot" Background ="White" Height ="479" WIDth ="485" >
< TextBox Height ="87" HorizontalAlignment ="left" margin ="12,347,0" name ="txtMessage" VerticalAlignment ="top" WIDth ="335" />
< button Content ="发送" Height ="29" HorizontalAlignment ="Right" margin ="0,440,138,0" name ="btnSend" VerticalAlignment ="top" WIDth ="61" />
< ListBox Height ="317" HorizontalAlignment ="left" ItemsSource =" {Binding MessageInfo,Mode=OneWay} " name ="ListMsgs" VerticalAlignment ="top" WIDth ="335" margin ="12,12,0" >
< ListBox.ItemTemplate >
< DataTemplate >
< StackPanel OrIEntation ="Horizontal" >
< TextBlock Text =" {Binding SendTime,StringFormat='HH:mm:ss'} " ></ TextBlock >
< TextBlock Text =" " ></ TextBlock >
< TextBlock Text =" {Binding Sender} " WIDth ="60" ></ TextBlock >
< TextBlock Text =" : " ></ TextBlock >
< TextBlock Text =" {Binding Message} " FontSize ="12" FontFamily ="Verdana" Foreground ="Chocolate" ></ TextBlock >
</ StackPanel >
</ DataTemplate >
</ ListBox.ItemTemplate >
</ ListBox >
< Image Height ="31" HorizontalAlignment ="left" Source ="Images/online.jpg" margin ="351,0" name ="image1" Stretch ="Fill" VerticalAlignment ="top" WIDth ="32" />
< button Content ="关闭" Height ="29" HorizontalAlignment ="left" margin ="219,0" name ="btnClose" VerticalAlignment ="top" WIDth ="61" />
< TextBox Height ="23" HorizontalAlignment ="left" margin ="389,17,0" name ="txtPartner" VerticalAlignment ="top" WIDth ="83" />
< Image Height ="28" HorizontalAlignment ="left" margin ="352,0" name ="image2" Source ="Images/online.jpg" Stretch ="Fill" VerticalAlignment ="top" WIDth ="31" />
< TextBox Height ="23" HorizontalAlignment ="left" margin ="389,349,0" name ="txtMe" VerticalAlignment ="top" WIDth ="83" />
</ GrID >
</ UserControl >

 

后台代码中需要从HTML中接收聊天对象:

代码 namespace ChatSL
{
public partial class Chat : UserControl
{
string user;
string partner;

EndpointAddress address ;
PollingDuplexhttpBinding binding;
ChatService.ChatServiceClIEnt proxy;

public Chat()
{
InitializeComponent();

this .Loaded += new RoutedEventHandler(Chat_Loaded);
this .txtMessage.KeyDown += new KeyEventHandler(KeyDownProcess);
this .btnSend.Click += new RoutedEventHandler(btnSend_Click);
this .btnClose.Click += new RoutedEventHandler(btnClose_Click);
}

voID Chat_Loaded( object sender,RoutedEventArgs e)
{
HTMLElement element;
element
= HTMLPage.document.GetElementByID( " lbluser " );
this .txtMe.Text = element.GetAttribute( " innerText " );
element
= HTMLPage.document.GetElementByID( " lblpartner " );
this .txtPartner.Text = element.GetAttribute( " innerText " );

user
= this .txtMe.Text;
partner
= this .txtPartner.Text;

LogIn();
}
//向服务器示意上线
private voID LogIn()
{
address
= new EndpointAddress( " http://localhost:32662/ChatService.svc%22);
binding = new PollingDuplexhttpBinding(PollingDuplexMode.MultipleMessagesPerPoll);
proxy
= new ChatService.ChatServiceClIEnt(binding,address);
proxy.ReceiveMessagesReceived
+= new EventHandler < ChatService.ReceiveMessagesReceivedEventArgs > (proxy_ReceiveMessagesReceived);
proxy.LoginChatAsync(user,partner);
}

#region 绑定数据
voID proxy_ReceiveMessagesReceived( object sender,ChatService.ReceiveMessagesReceivedEventArgs e)
{
this .ListMsgs.ItemsSource = e.ListMessages;
}

private voID SetDataSource()
{

}
#endregion

#region 键盘事件
protected voID KeyDownProcess( object sender,KeyEventArgs e)
{
if (e.Key == Key.Enter)
{
SendMessage();
}
}
#endregion
#region 发送信息
private voID btnSend_Click( object sender,RoutedEventArgs e)
{
SendMessage();
}
private voID SendMessage()
{
if ( this .txtMessage.Text == "" )
{
MessageBox.Show(
" 请输入信息! " );
return ;
}

ChatService.MessageInfo message
= new ChatService.MessageInfo();
message.ID
= GuID.NewGuID().ToString();
message.Receipt
= 0 ;
message.ReceiveMode
= " user " ;
message.ReceiveOrgan
= "" ;
message.ReceiveUser
= this .txtPartner.Text;
message.Message
= this .txtMessage.Text;
message.Sender
= this .txtMe.Text;
message.SendTime
= DateTime.Now;
message.source
= " web " ;
message.State
= 0 ;
message.Title
= this .txtMessage.Text;

proxy
= new ChatService.ChatServiceClIEnt(binding,address);
proxy.SendMessageCompleted
+= new EventHandler < ChatService.SendMessageCompletedEventArgs > (SendMessageComleted);
proxy.SendMessageAsync(message);

this .txtMessage.Text = "" ;
}
voID SendMessageComleted( object sender,ChatService.SendMessageCompletedEventArgs e)
{
if (e.Error == null )
{
// MessageBox.Show(e.Result.ToString());
}
}
#endregion

#region 关闭窗口
private voID btnClose_Click( object sender,EventArgs e)
{

}
#endregion
}
}
效果图:

 

源代码(包含视频部分):http://files.cnblogs.com/wengyuli/Chat_%e5%8f%8c%e5%b7%a5http.7z

 

http://www.cnblogs.com/wengyuli/archive/2010/06/19/silverlight-wcf-duplex.html

总结

以上是内存溢出为你收集整理的Silverlight与WCF之间的通信(2)利用WCF的双工通信“推送”给SL数据全部内容,希望文章能够帮你解决Silverlight与WCF之间的通信(2)利用WCF的双工通信“推送”给SL数据所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/web/1071604.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-26
下一篇 2022-05-26

发表评论

登录后才能评论

评论列表(0条)

保存