轉帖|其它|編輯:郝浩|2011-01-18 14:39:58.000|閱讀 1476 次
概述:上一個隨筆記錄了SL利用Timer定時去WCF上取數據再綁定到界面上的問題,今天嘗試用了WCF的Duplex雙工通信來做這個事情,也以這個例子來說明WCF中Duplex的使用。
# 界面/圖表報表/文檔/IDE等千款熱門軟控件火熱銷售中 >>
一、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;
//開始聊天
public bool LoginChat(string User, string Partner)
{
try
{
chatserviceCallBack = OperationContext.Current.GetCallbackChannel<IChatServiceCallBack>();
_user = User;
_partner = Partner;
Timer 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="//schemas.microsoft.com/winfx/2006/xaml/presentation%22
xmlns:x="//schemas.microsoft.com/winfx/2006/xaml%22
xmlns:d="//schemas.microsoft.com/expression/blend/2008%22
xmlns:mc="//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="發送" 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="關閉" 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中接收聊天對象:
#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
}
}
效果圖:
本站文章除注明轉載外,均為本站原創或翻譯。歡迎任何形式的轉載,但請務必注明出處、不得修改原文相關鏈接,如果存在內容上的異議請郵件反饋至chenjj@fc6vip.cn
文章轉載自:網絡轉載