zoukankan      html  css  js  c++  java
  • WCF Service Contract之MEPs

     

    WCF Service ContractMEPs

    LazyBee

    WCF支持的消息交换模式MEPs(Message Exchange Partten)为三种:请求-响应模式(Request-Replay), 单向模式(One Way),双向模式(Duplex.

    [ServiceContract(SessionMode=SessionMode.Required)]

    public interface ICalculatorSession

    {                        

        [OperationContract(IsOneWay = true)]

        void AddTo(double n);

        [OperationContract]

        double Equals();

    }

    以上AddTo方法就是单向模式,而Equals就是双向模式。(缺省的IsOneWay的值是false

    缺省的消息交换模式就是Request-Replay模式。 

    注意:如果指定的方法的消息交换模式是One Way,那么这个方法的返回值必须是void,并且不能有outref的参数。当WCF服务的客户端不应该等到对应的操作的完成并且也不需要处理SOAP错误时,采用这种单向模式。(这个方法的返回值是void并不代表该方法会返回消息给调用者。) 

    Duplex模式是客户端和服务之间可以相互独立的使用One WayRequest-Replay进行双向通讯的消息交换模式。 

    在使用Duplex进行消息交换的时候,并且客户端调用的是定义为Request-Reply的服务操作,而且在这个服务操作中又调用客户端的另外一个Request-Reply的一个回调方法,这时就会遇到如下错误,你可以根据提示进行修复操作。

    错误:This operation would deadlock because the reply cannot be received until the current Message completes processing. If you want to allow out-of-order message processing, specify ConcurrencyMode of Reentrant(可重入的并发模式) or Multiple on ServiceBehaviorAttribute.

     以下是来自微软的例子中的一个Duplex方式的程序,经过稍加改动(红色的方法是增加的代码):

    //服务器端代码
    =================================================================
    using System;
    using System.ServiceModel;
    namespace Microsoft.ServiceModel.Samples
    {
        
    // Define a duplex service contract.
        
    // A duplex contract consists of two interfaces.
        
    // The primary interface is used to send messages from the client to the service.
        
    // The callback interface is used to send messages from the service back to the client.
        
    // ICalculatorDuplex allows one to perform multiple operations on a running result.
        
    // The result is sent back after each operation on the ICalculatorCallback interface.
        [ServiceContract(Namespace = "http://Microsoft.ServiceModel.Samples", SessionMode=SessionMode.Required, CallbackContract=typeof(ICalculatorDuplexCallback))]
        
    public interface ICalculatorDuplex
        
    {
            [OperationContract(IsOneWay 
    = true)]
            
    void Clear();
            [OperationContract(IsOneWay 
    = true)]
            
    void AddTo(double n);
            [OperationContract(IsOneWay 
    = true)]
            
    void SubtractFrom(double n);
            [OperationContract(IsOneWay 
    = true)]
            
    void MultiplyBy(double n);
            [OperationContract(IsOneWay 
    = true)]
            
    void DivideBy(double n);

            [OperationContract]
            String Request_ReplayMethodInDuplex(
    int i);
        }


        
    // The callback interface is used to send messages from service back to client.
        
    // The Result operation will return the current result after each operation.
        
    // The Equation opertion will return the complete equation after Clear() is called.
        public interface ICalculatorDuplexCallback
        
    {
            [OperationContract(IsOneWay 
    = true)]
            
    void Result(double result);
            [OperationContract(IsOneWay 
    = true)]
            
    void Equation(string eqn);
            [OperationContract(IsOneWay
    =true)]
            
    void ShowMessage(string s);
        }


        
    // Service class which implements a duplex service contract.
        
    // Use an InstanceContextMode of PerSession to store the result
        
    // An instance of the service will be bound to each duplex session
        [ServiceBehavior(InstanceContextMode = InstanceContextMode.PerSession)]
        
    public class CalculatorService : ICalculatorDuplex
        
    {
            
    double result = 0.0D;  string equation;
            
    public CalculatorService()
            
    {
                equation 
    = result.ToString();
            }


            
    public void Clear()
            
    {
                Callback.Equation(equation 
    + " = " + result.ToString());
                equation 
    = result.ToString();
            }


            
    public void AddTo(double n)
            
    {
                result 
    += n;
                equation 
    += " + " + n.ToString();
                Callback.Result(result);
            }


            
    public void SubtractFrom(double n)
            
    {
                result 
    -= n;
                equation 
    += " - " + n.ToString();
                Callback.Result(result);
            }


            
    public void MultiplyBy(double n)
            
    {
                result 
    *= n;
                equation 
    += " * " + n.ToString();
                Callback.Result(result);
            }


            
    public void DivideBy(double n)
            
    {
                result 
    /= n;
                equation 
    += " / " + n.ToString();
                Callback.Result(result);
            }


            ICalculatorDuplexCallback Callback
            
    {
                
    get
                
    {
                    
    return OperationContext.Current.GetCallbackChannel<ICalculatorDuplexCallback>();
                }

            }

            
    public string Request_ReplayMethodInDuplex(int i)
            
    {
                Callback.ShowMessage(
    "Hello World!" + i);
                
    return "hello world " + i;
            }

        }

    }

     

    //Web.Config的内容
    ===============================================================================================================
    <?xml version="1.0" encoding="utf-8" ?>
    <configuration>
      
    <system.serviceModel>
        
    <services>
          
    <service 
              
    name="Microsoft.ServiceModel.Samples.CalculatorService"
              behaviorConfiguration
    ="CalculatorServiceBehavior">
            
    <!-- This endpoint is exposed at the base address provided by host: http://localhost/servicemodelsamples/service.svc  -->
            
    <endpoint address=""
                        binding
    ="wsDualHttpBinding"
                        contract
    ="Microsoft.ServiceModel.Samples.ICalculatorDuplex" />
            
    <!-- the mex endpoint is exposed at http://localhost/servicemodelsamples/service.svc/mex -->
            
    <endpoint address="mex"
                      binding
    ="mexHttpBinding"
                      contract
    ="IMetadataExchange" />
          
    </service>
        
    </services>

        
    <!--For debugging purposes set the includeExceptionDetailInFaults attribute to true-->
        
    <behaviors>
          
    <serviceBehaviors>
            
    <behavior name="CalculatorServiceBehavior">
              
    <serviceMetadata httpGetEnabled="True"/>
              
    <serviceDebug includeExceptionDetailInFaults="True" />
            
    </behavior>
          
    </serviceBehaviors>
        
    </behaviors>

      
    </system.serviceModel>

      
    <system.web>
        
    <compilation debug="true"/>
      
    </system.web>
    </configuration>

    //Service.svc的内容

    ===================================================================================

    <%@ServiceHost language=c# Debug="true" Service="Microsoft.ServiceModel.Samples.CalculatorService" %>

     如何运行这个服务?

    1 首先在IIS中创建一个http://localhost/servicemodelsamples的虚拟目录。

    2 如果你是第一次运行WCF Service的话,需要将.svc扩展名和aspnet_isapi.dll关联,具体操作如下:

    1.        打开IIS管理器.

    2.        右单击 Web Sites 并且选择属性 Properties.

    3.        On the Home Directory tab, click 配置Configuration.

    4.        In the list of application mappings, verify that the .svc file is mapped to the aspnet_isapi.dll. If the file has not been mapped:

    a.                  单击增加按钮.

    b.                  Add/Edit Application Extension Mapping 对话框中, 单击浏览按钮

    c.                   找到aspnet_isapi.dll并单击Open.

    d.                  制定 .svc 扩展名

    e.                  确保Check that file exists 选项没有被选中.

    f.                    单击确定, 然后再单击确定回到站点属性窗口.

    5.        单击确定关闭站点属性窗口。

    3然后就可以在IE窗口中测试时候正常运行了。(http://localhost/servicemodelsamples/service.svc.

     如何方便的产生客户端?

    由于VS2008自带的WCFTestClient.exe不能测试duplex模式的WCF Service,所以必须手动来产生客户端测试,为了方便应对服务契约的变更,可以在client 的项目属性的Build Events中的Pre-Build event command line的文本框中增加如下命令以帮助自动生成客户端的代理类:

    Call "D:\Program Files\Microsoft Visual Studio 9.0\VC\vcvarsall.bat" x86 

    svcutil /language:cs /noconfig /out:$(ProjectDir)generatedClient.cs /n:*,Microsoft.ServiceModel.Samples http://localhost/servicemodelsamples/service.svc?wsdl

     客户端的实现文件如下:

    ============================================================================================================

    using System;
    using System.ServiceModel;

    namespace Microsoft.ServiceModel.Samples
    {
        
    // The service contract is defined in generatedClient.cs, generated from the service by the svcutil tool.

        
    // Define class which implements callback interface of duplex contract
        public class CallbackHandler : ICalculatorDuplexCallback
        
    {
            
    public void Result(double result)
            
    {
                Console.WriteLine(
    "Result({0})", result);
            }

            
    public void Equation(string eqn)
            
    {
                Console.WriteLine(
    "Equation({0})", eqn);
            }

            
    public void ShowMessage(string s)
            
    {
                Console.WriteLine(
    "ZXG:" + s);
            }
            
        }


        
    class Client
        
    {
            
    static void Main()
            
    {
                
    // Construct InstanceContext to handle messages on callback interface
                InstanceContext instanceContext = new InstanceContext(new CallbackHandler());

                
    // Create a client
                CalculatorDuplexClient client = new CalculatorDuplexClient(instanceContext);

                Console.WriteLine(
    "Press <ENTER> to terminate client once the output is displayed.");
                Console.WriteLine();

                
    // Call the AddTo service operation.
                double value = 100.00D;
                client.AddTo(value);
                
    // Call the SubtractFrom service operation.
                value = 50.00D;
                client.SubtractFrom(value);
                
    // Call the MultiplyBy service operation.
                value = 17.65D;
                client.MultiplyBy(value);
                
    // Call the DivideBy service operation.
                value = 2.00D;
                client.DivideBy(value);
                
    // Complete equation
                client.Clear();

                Console.WriteLine(client.Request_ReplayMethodInDuplex(
    2));
                
                
    //Closing the client gracefully closes the connection and cleans up resources
                client.Close();
                Console.ReadLine();
            }

        }

    }

    以下是客户端的配置文件:

    <?xml version="1.0" encoding="utf-8" ?>
    <configuration>
      
    <system.serviceModel>
        
    <client>
          
    <endpoint name=""
                    address
    ="http://localhost/servicemodelsamples/service.svc" 
                    binding
    ="wsDualHttpBinding" 
                    bindingConfiguration
    ="DuplexBinding" 
                    contract
    ="Microsoft.ServiceModel.Samples.ICalculatorDuplex" />
        
    </client>
        
        
    <bindings>
          
    <!-- configure a binding that support duplex communication -->
          
    <wsDualHttpBinding>
            
    <binding name="DuplexBinding" 
                     clientBaseAddress
    ="http://localhost:8000/myClient/">
            
    </binding>
          
    </wsDualHttpBinding>
        
    </bindings>  
      
    </system.serviceModel>
    </configuration>

     注意:在客户端代码中Console.WriteLine(client.Request_ReplayMethodInDuplex(2))的这行代码将调用服务端的Request-ReplyRequest_ReplayMethodInDuplex服务操作,并且在Request_ReplayMethodInDuplex的实现中又调用了的客户端的One WayShowMessage回调方法。这个调用运行的非常正常。如果将ShowMessage回调方法变成Request-Replay方式(去掉OperationContract中的IsOneWay=true,或者将其值更改成false),在执行代码Console.WriteLine(client.Request_ReplayMethodInDuplex(2))的时候将出现前面所说的错误。

    This operation would deadlock because the reply cannot be received until the current Message completes processing. If you want to allow out-of-order message processing, specify ConcurrencyMode of Reentrant(可重入的并发模式) or Multiple on ServiceBehaviorAttribute.

  • 相关阅读:
    MySQL 数据库改名的简单方法
    Apache启用Gzip压缩
    安全的Web主机iptables防火墙脚本
    iptables
    Linux服务器维护统计连接数查看外部IP
    面试相关(新)
    hdu 4946 Area of Mushroom (凸包,去重点,水平排序,留共线点)
    凸包全解
    eclipse (android环境搭建)
    wins 软件安装
  • 原文地址:https://www.cnblogs.com/LazyBee/p/1041647.html
Copyright © 2011-2022 走看看