zoukankan      html  css  js  c++  java
  • 学习 WCF By Visual Studio 2010 (1)起步“全双工”

     零起点学吧,以前想学.NET Remoting,我懒人一个到现在也没开始学,这倒好直接WCF吧。 

    (一)起步“全双工”(Duplex)

     1 建立一个 服务契约在Visual Studio 中建立一个 “WCF Service Library” 项目 

    1.1 建立一个 服务接口 就叫 "ISendMessageService" 吧

     1 namespace MessageService
     2 {
     3     [ServiceContract(
     4         Name = "SendMessageService",
     5         Namespace = "SendMessageServiceNameSpace",
     6         SessionMode = SessionMode.Required,
     7         CallbackContract = typeof(IMessageCallback))]
     8     public interface ISendMessageService
     9     {
    10         [OperationContract]
    11         string SendMessage(string value);
    12 
    13     }
    14 }

     1.2 实现这个接口

     1  public class MessageService : ISendMessageService
     2     {
     3         private static List<IMessageCallback> _callbackList = new List<IMessageCallback>();
     4         
     5         #region ISendMessageService Members
     6 
     7         public string SendMessage(string message)
     8         {
     9             IMessageCallback callBack = OperationContext.Current.GetCallbackChannel<IMessageCallback>();
    10             
    11             if (!_callbackList.Contains(callBack))
    12             {
    13                 _callbackList.Add(callBack);
    14             }
    15 
    16             _callbackList.ForEach(
    17                 delegate(IMessageCallback callback)
    18                 { callback.NotifyUI(message); });
    19             return string.Format("Send message at{0}:{1}", DateTime.Now, message);
    20         }
    21         #endregion
    22     }

    1.3 建立Callback 接口

    1 //[ServiceContract(CallbackContract=typeof(IMessageCallback))]指明ICallback是一个服务契约了,
    2     //所以IMessageCallback不再需要添加ServiceContractAttribute特性。
    3     public interface IMessageCallback
    4     {
    5         //由于服务端不需要回调的返回值,索性将回调操作也设为单向方法。
    6         [OperationContract(IsOneWay = true)]
    7         void NotifyUI(string message);
    8     }

    1.4 服务端配置文件:

     1 <?xml version="1.0"?>
     2 <configuration>
     3   <system.serviceModel>
     4     <services>
     5       <service name="MessageService.MessageService">
     6         <endpoint address="Service" binding="wsDualHttpBinding" contract="MessageService.ISendMessageService" name="HttpBinding">
     7           <identity>
     8             <dns value="localhost"/>
     9           </identity>
    10         </endpoint>
    11         <endpoint address="Service" binding="netTcpBinding" contract="MessageService.ISendMessageService" name="TcpBinding">
    12           <identity>
    13             <dns value="localhost"/>
    14           </identity>
    15         </endpoint>
    16         <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>
    17         <host>
    18           <baseAddresses>
    19             <add baseAddress="http://localhost:8732/SendMessage/MessageService/"/>
    20             <add baseAddress="net.tcp://localhost:8733/SendMessage/MessageService/"/>
    21           </baseAddresses>
    22         </host>
    23       </service>
    24     </services>
    25     <behaviors>
    26       <serviceBehaviors>
    27         <behavior>
    28           <serviceMetadata httpGetEnabled="True"/>
    29           <serviceDebug includeExceptionDetailInFaults="False"/>
    30         </behavior>
    31       </serviceBehaviors>
    32     </behaviors>
    33   </system.serviceModel>
    34 </configuration>

    2 建立客户端

     2.1 添加 Service References 

     2.2 如果是 通过 Http 实现 Duplex 则还需要修改 App.config 否则在Xp sp2 下回报 80端口已经被占用的异常。

     clientBaseAddress="http://localhost:9999/MyClient

     1 <wsDualHttpBinding>
     2                 <binding name="HttpBinding" closeTimeout="00:01:00" openTimeout="00:01:00"
     3                     receiveTimeout="00:10:00" sendTimeout="00:01:00" bypassProxyOnLocal="false"
     4                     transactionFlow="false" hostNameComparisonMode="StrongWildcard"
     5                     maxBufferPoolSize="524288" maxReceivedMessageSize="65536"
     6                     messageEncoding="Text" textEncoding="utf-8" useDefaultWebProxy="true" clientBaseAddress="http://localhost:9999/MyClient">
     7                     <readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384"
     8                         maxBytesPerRead="4096" maxNameTableCharCount="16384" />
     9                     <reliableSession ordered="true" inactivityTimeout="00:10:00" />
    10                     <security mode="Message">
    11                         <message clientCredentialType="Windows" negotiateServiceCredential="true"
    12                             algorithmSuite="Default" />
    13                     </security>
    14                 </binding>
    15             </wsDualHttpBinding>

     2.3 客户端建立 Service Reference 实体:

    1  private void Client_Load(object sender, EventArgs e)
    2         {
    3             _sendMessageServiceClient = new SendMessageServiceClient(new InstanceContext(this), "TcpBinding");
    4             _sendMessageServiceClient.Open();
    5         }

    2.4 调用服务端方法。

    1 private void btn_Send_Click(object sender, EventArgs e)
    2         {
    3             txt_receive.Text = _sendMessageServiceClient.SendMessage(txt_Message.Text);
    4         }

    2.5 实现回调接口 SendMessageServiceCallback

    1 public partial class Client : Form, SendMessageServiceCallback
    2     {
    3         private SendMessageServiceClient _sendMessageServiceClient;
    4         private SynchronizationContext _uiSyncContext = null;
    5 
    6         public Client()
    7         {
    8             InitializeComponent();
    9         }
    1 
    2 #region SendMessageServiceCallback Members
    3 
    4         void SendMessageServiceCallback.NotifyUI(string guestName)
    5         {
    6             txt_Callbacktest.Text = guestName;
    7         }
    8 
    9         #endregion

    大功告成! 这一下就可以在回调的时候更改txt_Callbacktest.Text 属性了。

    可是真的这么顺利么?.....

    问题:TimeOut!! 

    为什么会 TimeOut?  转自tomore的日志

    我们现在来分析是什么导致了TimeoutException的抛出。原因很简单:由于我们对service的调用的是在UI 线程调用的,所以在开始调用到最终得到结果,这个UI Thread会被锁住;但是当service进行了相应的运算的到运算的结果后,需要调用callback对象对client进行回调,默认的情况下,Callback的执行是在UI线程执行的。当Callback试图执行的时候,发现UI 线程被锁,只能等待。这样形成一个死锁,UI线程需要等待CalculateService执行返回后才能解锁,而CalculateService需要Callback执行完成;而Callback需要等到UI线程解锁才能执行。

    更多的请参见: 

    http://www.winu.cn/space-14160-do-blog-id-25131.html

    —————————————————————————————————————————————————————————————— 

     学习资源:

    WCF从理论到实践

    http://kb.cnblogs.com/page/43709/

    《我的WCF之旅》博文系列汇总

    http://www.cnblogs.com/artech/archive/2007/09/15/893838.html 

  • 相关阅读:
    网上搜的逆元知识
    关于树的一点学习【清北学堂】
    矩阵乘法和斐波那契数列【清北学堂】
    Luogu【P1130】红牌(DP)
    Luogu【P1901】发射站(单调栈)
    Oracle_PL/SQL(1) 匿名块
    Oracle_SQL(7) 复杂查询
    Oracle_SQL(6) 单行函数
    Oracle_SQL(5) 连接和子查询
    Oracle_SQL(4) DDL 表和约束
  • 原文地址:https://www.cnblogs.com/windyliu/p/1722115.html
Copyright © 2011-2022 走看看