【转】利用WCF的双工通信
Silverlight與WCF之間的通信(2)利用WCF的雙工通信“推送”給SL數(shù)據(jù)
作者:Leon Weng??來源:博客園??發(fā)布時間:2010-06-19 23:43??閱讀:2215 次??原文鏈接?? [收藏]??一,Duplex簡介
上一個隨筆記錄了SL利用Timer定時去WCF上取數(shù)據(jù)再綁定到界面上的問題,今天嘗試用了WCF的Duplex雙工通信來做這個事情,也以這個例子來說明WCF中Duplex的使用。
雙工通信的原理很簡單,我們平時用的是客戶端調(diào)用服務(wù)端的方法來獲取數(shù)據(jù),而Duplex是將客戶端也當作了服務(wù)器,客戶端上的方法也可以被調(diào)用,以聊天功能為例子,用戶A連接到服務(wù)器后,之前的做法是客戶端定時取數(shù)據(jù),而Duplex是在服務(wù)端定時檢測數(shù)據(jù)變化,如果發(fā)現(xiàn)了發(fā)送給A的信息,那么立即會調(diào)用客戶端的方法來推送信息到A。
二,建立Duplex模式的WCF服務(wù)
這里以一個簡單的聊天功能來說明,WCF提供了三個方法,連接到服務(wù)器方法,發(fā)送信息方法和接收信息方法。從服務(wù)契約上來說分為兩個接口,分別是為客戶端提供發(fā)送信息和開始聊天方法的IChatService接口和服務(wù)器調(diào)用客戶端方法的IChatServiceCallBack接口
IChatService.cs文件
代碼 namespaceChatWCF?{?
???? [ServiceContract(CallbackContract=typeof(IChatServiceCallBack))]//這里需要定義IChatService接口的回調(diào)接口IChatServiceCallBack
publicinterfaceIChatService?
??? {?
??????? [OperationContract]?
??????? boolSendMessage(MessageInfo msg); //發(fā)送信息
??????? [OperationContract]?
??????? boolLoginChat(stringUser,stringPartner);//開始聊天模式??
}?
??? [ServiceContract]?
??? publicinterfaceIChatServiceCallBack //供服務(wù)端回調(diào)的接口
{?
??????? [OperationContract(IsOneWay=true)]?
??????? voidReceiveMessages(List<MessageInfo>listMessages);//客戶端被服務(wù)端回調(diào)后接收信息
}?
}
接下來需要實現(xiàn)這接口,IChatService.svc.cs
代碼 namespaceChatWCF?{?
???? publicclassChatService : IChatService?
???? {?
??????? IChatServiceCallBack chatserviceCallBack;?
??????? string_user;?
??????? string_partner;?
Timer timer;
//開始聊天
publicboolLoginChat(stringUser, stringPartner)
??????? {?
??????????? try
??????????? {?
??????????????? chatserviceCallBack =OperationContext.Current.GetCallbackChannel<IChatServiceCallBack>();?
??????????????? _user =User;?
??????????????? _partner =Partner;??
??????????????? timer =newTimer(newTimerCallback(CheckMessages), this, 100, 100);?
??????????????? returntrue;?
??????????? }?
??????????? catch(Exception ex)?
??????????? {?
??????????????? returnfalse;?
??????????? }?
??????? }?
//檢查消息并回調(diào)客戶端接收此消息,此處是回調(diào)的重點
??????? privatevoidCheckMessages(objecto) {?
??????????? chatserviceCallBack.ReceiveMessages(GetMessages(_user,_partner));?
??????? }?
//發(fā)送信息
publicboolSendMessage(MessageInfo msg)?
{
??????????????? [將MessageInfo寫入數(shù)據(jù)庫...]
}?
//檢測數(shù)據(jù)庫
privateList<MessageInfo>GetMessages(stringUser, stringPartner)?
{?
??????????? List<MessageInfo>listMsg =newList<MessageInfo>();
?? [檢測數(shù)據(jù)庫并返回檢測到的MessageInfo...]?????? returnlistMsg;?
}?
//執(zhí)行簡單的SQL語句
privateDataSet ExcuteSQL(stringstrSql)?
?????? {?
??????????? stringstrServer ="server=LEON-PC\\sql2005;database=jplan;uid=sa;pwd=sa;";?
??????????? SqlConnection con =newSqlConnection(strServer);?
??????????? con.Open();?
??????????? SqlDataAdapter dataAdapter =newSqlDataAdapter(strSql, con);?
??????????? DataSet ds =newDataSet();?
??????????? dataAdapter.Fill(ds);?
??????????? con.Close();?
??????????? returnds;?
??????? }?
??? }?
}
這里需要注意一點的是這個WCF是建立在Duplex基礎(chǔ)上的,所以在wcf的項目中需要添加一個程序集:
Assembly System.ServiceModel.PollingDuplex
??? C:\Program Files\Microsoft SDKs\Silverlight\v4.0\Libraries\Server\System.ServiceModel.PollingDuplex.dll
接下來需要對Web.config進行配置,主要是ServiceModel節(jié)點:
代碼 <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服務(wù)是一個單獨的站點,而客戶端是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服務(wù)會發(fā)現(xiàn)下圖,說明服務(wù)已經(jīng)正確host到VS的輕量級IIS上了
三,Silverlight跨域訪問WCF的Duplex服務(wù)
先建立一個單獨的project,silverlight app,當然還是需要先引用WCF服務(wù)的:
新建一個SL文件,Chat.xaml代碼,包括了一個發(fā)送消息窗口和一個顯示聊天信息的窗口,這個聊天的窗口從普通HTML街面上接收兩個參數(shù),即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,0"Name="txtMessage"VerticalAlignment="Top"Width="335"/>
??????? <Button Content="發(fā)送"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,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,12,0,0"Name="image1"Stretch="Fill"VerticalAlignment="Top"Width="32"/>
??????? <Button Content="關(guān)閉"Height="29"HorizontalAlignment="Left"Margin="219,440,0,0"Name="btnClose"VerticalAlignment="Top"Width="61"/>
??????? <TextBox Height="23"HorizontalAlignment="Left"Margin="389,17,0,0"Name="txtPartner"VerticalAlignment="Top"Width="83"/>
??????? <Image Height="28"HorizontalAlignment="Left"Margin="352,347,0,0"Name="image2"Source="Images/online.jpg"Stretch="Fill"VerticalAlignment="Top"Width="31"/>
??????? <TextBox Height="23"HorizontalAlignment="Left"Margin="389,349,0,0"Name="txtMe"VerticalAlignment="Top"Width="83"/>
??? </Grid>
</UserControl>
后臺代碼中需要從HTML中接收聊天對象:
代碼 namespaceChatSL?{?
??? publicpartialclassChat : UserControl?
??? {??
??????? stringuser;?
??????? stringpartner;?
??????? EndpointAddress address ;?
??????? PollingDuplexHttpBinding binding;?
??????? ChatService.ChatServiceClient proxy;?
??????? publicChat()?
??????? {?
??????????? InitializeComponent();
??????????? this.Loaded+=newRoutedEventHandler(Chat_Loaded);?
??????????? this.txtMessage.KeyDown +=newKeyEventHandler(KeyDownProcess);?
??????????? this.btnSend.Click +=newRoutedEventHandler(btnSend_Click);?
??????????? this.btnClose.Click +=newRoutedEventHandler(btnClose_Click);?
??????? }?
??????? voidChat_Loaded(objectsender,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();?
??????? }?
//向服務(wù)器示意上線
??????? privatevoidLogIn()?
??????? {?
??????????? address =newEndpointAddress("http://localhost:32662/ChatService.svc%22);
binding =newPollingDuplexHttpBinding(PollingDuplexMode.MultipleMessagesPerPoll);?
??????????? proxy =newChatService.ChatServiceClient(binding,address);?
??????????? proxy.ReceiveMessagesReceived+=newEventHandler<ChatService.ReceiveMessagesReceivedEventArgs>(proxy_ReceiveMessagesReceived);?
??????????? proxy.LoginChatAsync(user, partner);?
??????? }?
??????? #region綁定數(shù)據(jù)
??????? voidproxy_ReceiveMessagesReceived(objectsender,ChatService.ReceiveMessagesReceivedEventArgs e)?
??????? {?
??????????? this.listMsgs.ItemsSource =e.listMessages;?
??????? }?
??????? privatevoidSetDataSource()?
??????? {?
????????????
??????? }?
??????? #endregion
??????? #region鍵盤事件
??????? protectedvoidKeyDownProcess(objectsender, KeyEventArgs e)?
??????? {?
??????????? if(e.Key ==Key.Enter)?
??????????? {?
??????????????? SendMessage();?
??????????? }?
??????? }?
??????? #endregion
??????? #region發(fā)送信息
??????? privatevoidbtnSend_Click(objectsender, RoutedEventArgs e)?
??????? {?
??????????? SendMessage();?
??????? }?
??????? privatevoidSendMessage()?
??????? {?
??????????? if(this.txtMessage.Text =="")?
??????????? {?
??????????????? MessageBox.Show("請輸入信息!");?
??????????????? return;?
??????????? }?
??????????? ChatService.MessageInfo message =newChatService.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 =newChatService.ChatServiceClient(binding, address);?
??????????? proxy.SendMessageCompleted? +=newEventHandler<ChatService.SendMessageCompletedEventArgs>(SendMessageComleted);?
??????????? proxy.SendMessageAsync(message);?
??????????? this.txtMessage.Text ="";?
??????? }?
??????? voidSendMessageComleted(objectsender, ChatService.SendMessageCompletedEventArgs e)?
??????? {?
??????????? if(e.Error ==null)?
??????????? {?
??????????????? //MessageBox.Show(e.Result.ToString());
}?
??????? }?
??????? #endregion
??????? #region關(guān)閉窗口
??????? privatevoidbtnClose_Click(objectsender, EventArgs e)?
??????? {?
??????? }?
??????? #endregion
??? }?
}
效果圖:
源代碼(包含視頻部分):http://files.cnblogs.com/wengyuli/Chat_%e5%8f%8c%e5%b7%a5http.7z
轉(zhuǎn)載于:https://www.cnblogs.com/niuxiaohao/archive/2011/06/08/2075577.html
總結(jié)
以上是生活随笔為你收集整理的【转】利用WCF的双工通信的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 再发些CSS常用技巧和兼容方案
- 下一篇: PHP学习之路(一)工欲善其事,必先利其