zoukankan      html  css  js  c++  java
  • 【转载】WCF热门问题编程示例(4):WCF客户端如何异步调用WCF服务?

     

    WCF - IsOneWay 和异步的区别

    http://www.rainsts.net/article.asp?id=460

    在某些博客文章里,直接将 IsOneWay 称为 "异步方法"。虽然多数时候不会对开发带来什么问题,但深究起来,这两者是不同的。接下来,我们做个试验。将同一个服务契约分别用 IsOneWay 和异步进行实现,客户端使用多线程模拟并发调用,并使用 ServiceThrottlingBehavior (也可以使用 InstanceContextMode.Single) 进行并发控制。注意对比输出结果,我们就会发现其不同之处。

    IsOneWay版本

    [ServiceContract]
    public interface IService
    {
        [OperationContract(IsOneWay=true)]
        void Test();
    }
    
    public class MyService : IService
    {
        public void Test()
        {
            Console.WriteLine("Service BeginAdd:{0}", DateTime.Now);
            Thread.Sleep(5000);
            Console.WriteLine("Service EndAdd:{0}", DateTime.Now);
        }
    }
    
    public class WcfTest
    {
        public static void Test()
        {
            AppDomain.CreateDomain("Server").DoCallBack(delegate
            {
                ServiceHost host = new ServiceHost(typeof(MyService));
                host.AddServiceEndpoint(typeof(IService), new WSHttpBinding(), "http://localhost:8080/myservice");
    
                ServiceThrottlingBehavior throttling = new ServiceThrottlingBehavior();
                throttling.MaxConcurrentInstances = 1;
                host.Description.Behaviors.Add(throttling);
    
                host.Open();
            });
    
            for (int i = 0; i < 3; i++)
            {
                new Thread(delegate()
                {
                    IService channel = ChannelFactory<IService>.CreateChannel(new WSHttpBinding(),
                      new EndpointAddress("http://localhost:8080/myservice"));
    
                    using (channel as IDisposable)
                    {
                        Console.WriteLine("Client {0} BeginAdd:{1}", 
                            Thread.CurrentThread.ManagedThreadId, DateTime.Now);
    
                        channel.Test();
    
                        Console.WriteLine("Client {0} BeginAdd End:{1}", 
                            Thread.CurrentThread.ManagedThreadId, DateTime.Now);
                    }
                }).Start();
            }
        }
    }


    输出:
    Client 15 BeginAdd:2007-4-19 10:51:39
    Client 14 BeginAdd:2007-4-19 10:51:39
    Client 16 BeginAdd:2007-4-19 10:51:39
    Client 16 BeginAdd End:2007-4-19 10:51:40
    Service BeginAdd:2007-4-19 10:51:40
    Service EndAdd:2007-4-19 10:51:45

    Client 14 BeginAdd End:2007-4-19 10:51:46
    Service BeginAdd:2007-4-19 10:51:46
    Service EndAdd:2007-4-19 10:51:51
    Service BeginAdd:2007-4-19 10:51:51

    Client 15 BeginAdd End:2007-4-19 10:51:51
    Service EndAdd:2007-4-19 10:51:56

    异步版本

    [ServiceContract]
    public interface IService
    {
        [OperationContract]
        void Test();
    
        [OperationContract(AsyncPattern = true)]
        IAsyncResult BeginTest(AsyncCallback callBack, object state);
    
        void EndTest(IAsyncResult ar);
    }
    
    public class MyService : IService
    {
        public void Test()
        {
            Console.WriteLine("Service BeginAdd:{0}", DateTime.Now);
            Thread.Sleep(5000);
            Console.WriteLine("Service EndAdd:{0}", DateTime.Now);
        }
    
        public IAsyncResult BeginTest(AsyncCallback callBack, object state)
        {
            throw new Exception("The method or operation is not implemented.");
        }
    
        public void EndTest(IAsyncResult ar)
        {
            throw new Exception("The method or operation is not implemented.");
        }
    }
    
    public class WcfTest
    {
        public static void Test()
        {
            AppDomain.CreateDomain("Server").DoCallBack(delegate
            {
                ServiceHost host = new ServiceHost(typeof(MyService));
                host.AddServiceEndpoint(typeof(IService), new WSHttpBinding(), "http://localhost:8080/myservice");
    
                ServiceThrottlingBehavior throttling = new ServiceThrottlingBehavior();
                throttling.MaxConcurrentInstances = 1;
                host.Description.Behaviors.Add(throttling);
    
                host.Open();
            });
    
            for (int i = 0; i < 3; i++)
            {
                new Thread(delegate()
                {
                    IService channel = ChannelFactory<IService>.CreateChannel(new WSHttpBinding(),
                      new EndpointAddress("http://localhost:8080/myservice"));
    
                    using (channel as IDisposable)
                    {
                        Console.WriteLine("Client {0} BeginAdd:{1}", 
                            Thread.CurrentThread.ManagedThreadId, DateTime.Now);
    
                        IAsyncResult ar = channel.BeginTest(null, null);
    
                        Console.WriteLine("Client {0} BeginAdd End:{1}", 
                            Thread.CurrentThread.ManagedThreadId, DateTime.Now);
    
                        channel.EndTest(ar);
                    }
                }).Start();
            }
        }
    }


    输出:
    Client 14 BeginAdd:2007-4-19 10:53:56
    Client 16 BeginAdd:2007-4-19 10:53:56
    Client 15 BeginAdd:2007-4-19 10:53:56
    Client 16 BeginAdd End:2007-4-19 10:53:56
    Client 14 BeginAdd End:2007-4-19 10:53:56
    Client 15 BeginAdd End:2007-4-19 10:53:56
    Service BeginAdd:2007-4-19 10:53:59
    Service EndAdd:2007-4-19 10:54:04
    Service BeginAdd:2007-4-19 10:54:04
    Service EndAdd:2007-4-19 10:54:09
    Service BeginAdd:2007-4-19 10:54:09
    Service EndAdd:2007-4-19 10:54:14


    通过对比,我们发现异步方法 BeginXXX 调用并不受并发控制影响,调用后直接返回控制权;而 IsOneWay 则不同,它被阻塞直到服务方法获得执行才会返回(当然,没有等待服务方法执行完成)。这点区别在处理并发性能上,可能带来不同的效果,了解 IsOneWay 和异步的差别能让我们避免一些意外的问题。

    ------------------------------------------------------------------------

    WCF热门问题编程示例(4):WCF客户端如何异步调用WCF服务?

    How to call WCF Service asynchronously?

    【1】问题描述:

    WCF客户端如何异步调用WCF服务?

    How to call WCF Service asynchronously?

    关于WCF如何实现异步调用的问题,论坛上出现了很多帖子,也有很多讨论的文章,包括MSDN也给出了详细的学习资料和示例代码。但是很多资料过于笼统,MSDN的例子有点复杂。而我们实际项目中,要实现的需求,往往十分简单,就是要在客户端实现对于WCF服务操作的异步调用,也就是call WCF Service asynchronously。

    【2】资料收集:

         这里收集一些关于WCF异步调用比较有用的参考资料和问题连接。其实关于WCF客户端异步调用WCF服务的帖子很多,很多讨论反而走了弯路,我们想要的就是简单的异步调用WCF服务操作的例子。这里给出一些比较有价值的参考资料:

    【3】异步调用:

         这里需要了解的一个重要概念就是异步调用机制,在.NET里的异步调用机制是十分重要的一个知识点。另外就是回调的概念,这里也会使用到。.Net中的异步调用实际使用的是异步委托。异步委托将要执行的方法提交到.Net的线程池,由线程池中的线程来执行异步调用。

    【4】解决办法:

    知道了.NET异步调用的机制以后,我们就可以来尝试解决这个问题。这里本质是一样的。但编码的过程有点差别。

    1. 当然,最容易理解的就是我们自己写代码来实现异步调用。
    2. 其次,Visual Studio 2008已经提供了这个支持。这个更加方便。我给出截图:

    HowtoAddWCFServiceasynchronously

      我们这里给出的示例过程呢,是基于手写客户端异步调用代码的。仅供参考,当然你也可以使用Visual Studio来帮助完成这个过程。

    【5】服务端代码:

         服务端代码的实现十分简单,这里我们依然使用早期WCF的代码,定义一个IWCFService契约,包含一个操作SayHello,这个操作实现的功能,就是接受一name参数,然后打印返回字符串给客户端,为了演示,这里会打印出时间信息。具体代码如下:

    //1.服务契约
    [ServiceContract(Namespace = "http://www.cnblogs.com/frank_xl/")]
    public interface IWCFService
    {
        //操作契约
        [OperationContract]
        string SayHello(string name);

    }
    //2.服务类,继承接口。实现契约
    public class WCFService : IWCFService
    {
        //实现接口定义的方法
        public string SayHello(string name)
        {
            Console.WriteLine("Call Operation at {0}", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss:ffff"));
            return string.Format("Hello {0}",name);
        }
    }

    【6】客户端代码:

        客户端的实现大部分代码与之前的没有区别,为了方便,我们可以在Visual Studio生成的代码基础上修改。当然也完全可以自己重写。    这里比较重要的一点,就是要实现异步调用需要的契约以及异步调用的方法。

        【6.1】首先这里要实现支持异步调用的契约:

    public interface IWCFService {
        [System.ServiceModel.OperationContractAttribute(Action="
    http://www.cnblogs.com/frank_xl/IWCFService/SayHello", ReplyAction="http://www.cnblogs.com/frank_xl/IWCFService/SayHelloResponse")]
        string SayHello(string name);

        [OperationContract(AsyncPattern = true)]
        IAsyncResult BeginSayHello(string name, AsyncCallback callback, object asyncState);

        string EndSayHello(IAsyncResult result);
    }

        【6.2】支持异步调用的客户端代理类:

         我们要在自己的WCFClient代理类里继承这个契约,并提供异步操作调用的实现,具体代码如下:

    public string SayHello(string name) {
              return base.Channel.SayHello(name);
          }

          public IAsyncResult BeginSayHello(string name, AsyncCallback callback, object asyncState)
          {
              return Channel.BeginSayHello(name, callback, asyncState);
          }

          public string EndSayHello(IAsyncResult result)
          {
              return Channel.EndSayHello(result);
          }

        【6.3】测试客户端代码:

           客户端代码还有一点比较重要的地方,就是实现异步回调方法,这里我们在调用BeginSayHello方法的时候,不需要等待结果的返回,我们自己希望,WCF在调用完SayHello操作以后,执行一些必要的工作,比如显示返回结果,或者对返回的数据做更深入的处理,这里都需要使用到回调函数。我们也可以在回调方法里,来关闭WCF客户端,以释放资源。

           例子代码如下:

    /// <summary>
       /// This class is defined for WCF Async Call Test
       /// </summary>
       public class WCFClientTest
       {
           static public WCFServiceClient wcfServiceProxy = null;
           static void Main(string[] args)
           {
               Console.ForegroundColor = ConsoleColor.Yellow;

               WCFClientTest client = new WCFClientTest();
               wcfServiceProxy = new WCFServiceClient("WSHttpBinding_IWCFService");
               string name = "Frank Xu Lei";
               Console.WriteLine("Client Async Call begin at {0}",DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss:ffff"));
               //开始异步调用Begin Call
               wcfServiceProxy.BeginSayHello(name, client.OnCompletion, null);

               Console.WriteLine("press ENTER to exit…");
               Console.Read();

           }
           ////回调方法,Callback method
           void OnCompletion(IAsyncResult result)
           {
               string value = wcfServiceProxy.EndSayHello(result);
               Console.WriteLine("Returned value is {0} at {1}",value, DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss:ffff"));
               result.AsyncWaitHandle.Close();
               wcfServiceProxy.Close();
               Console.WriteLine("Asynchronous Calls is finished");
           }
       }

    【7】运行结果:

         这里启动宿主Host程序,然后运行WCF客户端即可,我们可以看到宿主端和客户端,异步调用操作的时间差别,打印窗口的截图如下:

    HowtocallWCFServiceasynchronously

  • 相关阅读:
    【SpringBoot1.x】SpringBoot1.x 安全
    WebStorm快捷键(Mac版)
    iOS 容联离线消息推送
    iOS使用TestFlight进行内部和外部人员测试
    iOS Runtime常用方法整理
    模仿斗鱼直播
    一个很好用的侧滑框架ICSDrawerController实现的 QQ 侧滑及换肤功能
    swift3.0 项目引导页
    使用 swift3.0高仿新浪微博
    swift 监听键盘弹出的高度
  • 原文地址:https://www.cnblogs.com/fx2008/p/2238906.html
Copyright © 2011-2022 走看看