zoukankan      html  css  js  c++  java
  • WCF 消息交换 转

    客户端和服务之间通过消息交换(Message Exchange)来完成方法调用和数据传递,WCF 定义了 3 种消息交换模式。

    1. Request/Reply

    这是缺省模式,又被称之为同步调用。在调用服务方法后需要等待服务的消息返回,即便该方法返回 void 类型。
    [ServiceContract]
    public interface IContract
    {
      [OperationContract]
      void Test();
    }

    public class MyService : IContract
    {
      public void Test()
      {
        Thread.Sleep(3000);
        Console.WriteLine("Test Execute:{0}", DateTime.Now);
      }
    }

    public class WcfTest
    {
      public static void Test()
      {
        AppDomain.CreateDomain("Server").DoCallBack(delegate
        {
          ServiceHost host = new ServiceHost(typeof(MyService));
          host.AddServiceEndpoint(typeof(IContract), new BasicHttpBinding(),
            "http://localhost:8080/myservice");

          host.Open();
        });

        ChannelFactory<IContract> factory = new ChannelFactory<IContract>(new BasicHttpBinding(),
          "http://localhost:8080/myservice");
        IContract o = factory.CreateChannel();

        Console.WriteLine("Start:{0}", DateTime.Now);
        o.Test();
        Console.WriteLine("End:{0}", DateTime.Now);
      }
    }

    输出:
    Start:2007-3-27 15:26:07
    Test Execute:2007-3-27 15:26:10
    End:2007-3-27 15:26:10

    2. one-way

    这种方式在调用方法后会立即返回,非常类似于异步行为。不过需要注意的是 one-way 不能用在非void,或者包含 out/ref 参数的方法上,会导致抛出 InvalidOperationException 异常。
    [ServiceContract]
    public interface IContract
    {
      [OperationContract(IsOneWay=true)]
      void Test();
    }

    public class MyService : IContract
    {
      public void Test()
      {
        Thread.Sleep(3000);
        Console.WriteLine("Test Execute:{0}", DateTime.Now);
      }
    }

    public class WcfTest
    {
      public static void Test()
      {
        AppDomain.CreateDomain("Server").DoCallBack(delegate
        {
          ServiceHost host = new ServiceHost(typeof(MyService));
          host.AddServiceEndpoint(typeof(IContract), new BasicHttpBinding(),
            "http://localhost:8080/myservice");    
          host.Open();
        });

        ChannelFactory<IContract> factory = new ChannelFactory<IContract>(
          new BasicHttpBinding(), "http://localhost:8080/myservice");
        IContract o = factory.CreateChannel();

        Console.WriteLine("Start:{0}", DateTime.Now);
        o.Test();
        Console.WriteLine("End:{0}", DateTime.Now);
      }
    }

    输出:
    Start:2007-3-27 15:27:18
    End:2007-3-27 15:27:18
    Test Execute:2007-3-27 15:27:21

    3. duplex

    这种模式相对复杂一些,我们详细描述一下步骤:

    (1) 设计标准的服务契约。为了完成回调操作,我们必须指定 SessionMode 和回调类型。
    [ServiceContract(SessionMode=SessionMode.Required, CallbackContract=typeof(ICallback))]
    public interface IContract
    {
      [OperationContract]
      void Test();
    }

    (2) 设计回调接口类型。由于回调方法在客户端执行,因此无须添加 ServiceContractAttribute。对于回调操作,服务器无须获取其返回信息,因此添加 IsOneWay=true 特性参数。
    public interface ICallback
    {
      [OperationContract(IsOneWay=true)]
      void Call(DateTime d);
    }

    (3) 实现服务契约。通过 OperationContext.Current.GetCallbackChannel 可以获取回调委托,进而完成调用。
    public class MyService : IContract
    {
      ICallback callback = OperationContext.Current.GetCallbackChannel<ICallback>();

      public void Test()
      {
        Console.WriteLine("Test AppDomain:{0}", AppDomain.CurrentDomain.FriendlyName);
        callback.Call(DateTime.Now);
      }
    }

    (4) 实现服务器。注意必须使用支持 Session 的 Binding 类型。
    ServiceHost host = new ServiceHost(typeof(MyService));
    host.AddServiceEndpoint(typeof(IContract), new WSDualHttpBinding(), "http://localhost:8080/myservice");
    host.Open();

    (5) 创建客户端代理对象。利用 Svcutil 或者我们前面讲的方法创建客户端代理类型代码。(为显示方便,代码有所删减。)
    //------------------------------------------------------------------------------
    // <auto-generated>
    //   此代码由工具生成。
    //   运行库版本:2.0.50727.42
    //
    //   对此文件的更改可能会导致不正确的行为,并且如果
    //   重新生成代码,这些更改将会丢失。
    // </auto-generated>
    //------------------------------------------------------------------------------

    [GeneratedCodeAttribute("System.ServiceModel", "3.0.0.0")]
    [ServiceContractAttribute(ConfigurationName = "IContract", CallbackContract = typeof(IContractCallback), SessionMode = SessionMode.Required)]
    public interface IContract
    {
      [OperationContractAttribute(Action = "...", ReplyAction = "...")]
      void Test();
    }

    [GeneratedCodeAttribute("System.ServiceModel", "3.0.0.0")]
    public interface IContractCallback
    {
      [OperationContractAttribute(IsOneWay = true, Action = "...")]
      void Call(System.DateTime d);
    }

    [GeneratedCodeAttribute("System.ServiceModel", "3.0.0.0")]
    public interface IContractChannel : IContract, IClientChannel
    {
    }

    [DebuggerStepThroughAttribute()]
    [GeneratedCodeAttribute("System.ServiceModel", "3.0.0.0")]
    public partial class ContractClient : DuplexClientBase<IContract>, IContract
    {
      public void Test()
      {
        base.Channel.Test();
      }
    }

    (6) 实现客户端。

    创建新的客户端项目,将生成的代理文件加入。客户端除了要创建一个实现回调接口的类型外,还要为绑定对象指定一个监听端口,以便服务器与之联系。
    class CallBack : IContractCallback
    {
      public void Call(DateTime d)
      {
        Console.WriteLine("Call AppDomain:{0}", AppDomain.CurrentDomain.FriendlyName);
        Console.WriteLine("Server DateTime:{0}", d);
      }
    }

    [STAThread]
    static void Main(string[] args)
    {
      WSDualHttpBinding binding = new WSDualHttpBinding();
      binding.ClientBaseAddress = new Uri("http://localhost:8081/client");
      EndpointAddress address = new EndpointAddress("http://localhost:8080/myservice");

      ContractClient client = new ContractClient(new InstanceContext(new CallBack()), binding, address);
      client.Test();
    }

    输出:

    Server
    --------------
    Test AppDomain:Server

    Client
    --------------
    Call AppDomain:Client.vshost.exe
    Server DateTime:2007-3-27 17:01:39
  • 相关阅读:
    JVM底层原理 内存模型+GC垃圾回收
    新Socket与网络小结
    Redis五大数据结构及基本指令用法
    MySql高级汇总-事务,索引,SQL调优,分库分表,读写分离
    笔试错题整理
    设计模式(思路)
    网络编程
    linux
    基础算法--KMP匹配字符串
    基础算法--整数二分
  • 原文地址:https://www.cnblogs.com/EasyLive2006/p/881574.html
Copyright © 2011-2022 走看看