欢迎访问 生活随笔!

生活随笔

当前位置: 首页 > 编程资源 > 编程问答 >内容正文

编程问答

【转】利用WCF的双工通信

发布时间:2025/7/25 编程问答 58 豆豆
生活随笔 收集整理的这篇文章主要介绍了 【转】利用WCF的双工通信 小编觉得挺不错的,现在分享给大家,帮大家做个参考.

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

作者:Leon Weng  来源:博客园  发布时间:2010-06-19 23:43  阅读:2215 次  原文链接   [收藏]  

一,Duplex简介

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

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

二,建立Duplex模式的WCF服务

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

IChatService.cs文件

代码 namespaceChatWCF 

     [ServiceContract(CallbackContract=typeof(IChatServiceCallBack))]//这里需要定义IChatService接口的回调接口IChatServiceCallBack
publicinterfaceIChatService 
    { 
        [OperationContract] 
        boolSendMessage(MessageInfo msg); //发送信息

        [OperationContract] 
        boolLoginChat(stringUser,stringPartner);//开始聊天模式  


    [ServiceContract] 
    publicinterfaceIChatServiceCallBack //供服务端回调的接口

        [OperationContract(IsOneWay=true)] 
        voidReceiveMessages(List<MessageInfo>listMessages);//客户端被服务端回调后接收信息

}

接下来需要实现这接口,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; 
            } 
        } 
//检查消息并回调客户端接收此消息,此处是回调的重点
        privatevoidCheckMessages(objecto) { 
            chatserviceCallBack.ReceiveMessages(GetMessages(_user,_partner)); 
        } 

//发送信息
publicboolSendMessage(MessageInfo msg) 
{
                [将MessageInfo写入数据库...]


//检测数据库
privateList<MessageInfo>GetMessages(stringUser, stringPartner) 

            List<MessageInfo>listMsg =newList<MessageInfo>();
   [检测数据库并返回检测到的MessageInfo...]       returnlistMsg; 


//执行简单的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基础上的,所以在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,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中接收聊天对象:

代码 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(); 
        } 
//向服务器示意上线
        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绑定数据
        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发送信息
        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关闭窗口
        privatevoidbtnClose_Click(objectsender, EventArgs e) 
        { 

        } 
        #endregion
    } 
}

效果图:

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

转载于:https://www.cnblogs.com/niuxiaohao/archive/2011/06/08/2075577.html

总结

以上是生活随笔为你收集整理的【转】利用WCF的双工通信的全部内容,希望文章能够帮你解决所遇到的问题。

如果觉得生活随笔网站内容还不错,欢迎将生活随笔推荐给好友。