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.

  • 相关阅读:
    centos7.6 安装与配置 MongoDB yum方式
    MongoDB 介绍
    centos 关闭selinux
    前端 HTML标签属性
    前端 HTML 标签嵌套规则
    前端 HTML 标签分类
    前端 HTML body标签相关内容 常用标签 表单标签 form里面的 input标签介绍
    前端 HTML body标签相关内容 常用标签 表单标签 form 表单控件分类
    前端 HTML form表单标签 select标签 option 下拉框
    POJ 1426
  • 原文地址:https://www.cnblogs.com/LazyBee/p/1041647.html
Copyright © 2011-2022 走看看