添加引用服务--高级--选中 生产异步操作

服务端接口操作

[OperationContract]
int Add(int a, int b);

客户端:

引用服务:在引用服务时,左下角点击“高级”按钮,勾选“生成异步操作”即可。

ServiceReference1.Service1Client   client= new ServiceReference1.Service1Client();
//int result = client.Add(5, 7); // 同步方法
client.AddCompleted += client_AddCompleted;
client.AddAsync(3, 2); // 异步方法

//另外一种异步调用方式:BeginXXX和EndXXX的方法

private void client_AddCompleted(object sender, AddCompletedEventArgs e)
{
try
{
int result = e.Result;

CalculateClient client = (CalculateClient)sender;
if (client != null)
{
// 释放资源。
client.Close();
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}

WCF入门(二)——异步操作

WCF是网络编程,既然是网络编程,那么就一般离不开异步操作了。异步操作按照发生源可以分为客户端异步和服务器端异步,本文就分别简单的介绍一下该如何实现。

一、客户端异步

以一个简单的服务为例:

[ServiceContract]
    public interface IService1
    {
        [OperationContract]
        string Foo();
    }

这个服务不用输入,仅仅返回一个字符串,通常的时候,我们喜欢和调用本地函数方式类似的以调用WCF服务,并且同步等待至远程返回结果。

var client = new WcfClient.Service.Service1Client();
    var result = client.Foo();
    Console.WriteLine(result);

一般来说,这个并没有什么问题;但是,和调用本地函数一样,如果该函数需要将长时间才能返回结果,则会阻塞线程,如果调用线程是UI线程的话则会导致UI没有响应。特别是像WCF这种远程调用的方式更会由于网络原因等导致耗时较长。

按照本地耗时函数的处理方式,我们可以借助Task来处理这个等待,然后获取返回值后,再通知界面。

var client = new WcfClient.Service.Service1Client();
    var result = await Task.Run(() => client.Foo());
    Console.WriteLine(result);

这个方式虽然不阻塞界面,但是消耗了一个Task在同步等待,效率不高。实际上,对于这种网络操作,VisualStudio在生成本地客户端代码的时候,就生成了异步方式访问的接口。

  

直接使用这个异步接口,就可以实现IO异步的方式访问,不用新开启一个Task来同步等待。

var client = new WcfClient.Service.Service1Client();
    var result = await client.FooAsync();
    Console.WriteLine(result);

关于默认的异步访问接口,也可以在根据服务生成本地代码的时候选择使用传统的BeginFoo,EndFoo的那种形式(由于远不如Task式的异步访问好用,不推荐)。

二、服务器端异步

服务器端异步指的主要是服务的异步实现,

以一个天气预报的WCF服务为例,假如我们要实现一个这样的接口:

public interface IService1
    {
        string QueryWeather(string city);
    }

由于我本地并没有天气预报的数据,要实现一个这样的服务,必须得到气象网站去查询,按照传统的同步方式,则实现如下:

public class Service1 : IService1
    {
        public string QueryWeather(string city)
        {
            var queryTask = QueryWeatherFromRemoteSite(city);
            queryTask.Wait();
            return queryTask.Result;
        }

static Task<string> QueryWeatherFromRemoteSite(string city)
        {
            //省略实现
        }
    }

很明显,每次一次处理QueryWeather的时候,都得阻塞当前线程至远程查询的完成,极大的浪费了系统资源。需要改成异步的方式实现。

传统的异步实现

在.Net 4.5前,要异步实现QueryWeather函数,必须得把接口声明成如下形式:

[ServiceContract]
    public interface IService1
    {
        [OperationContract(AsyncPattern = true)]
        IAsyncResultBeginQueryWeather(string city, AsyncCallback callback, object asyncState);
        string EndQueryWeather(IAsyncResult result);
    }

可以看到,和同步方式的契约声明不同的是:

  1. 在接口名称前加了一个Begin
  2. 设置了AsyncPattern = true

然后就要实现这个接口了,如下是一个简单的示例:

public class Service1 : IService1
    {
        #region IService1 成员

public IAsyncResult BeginQueryWeather(string city, AsyncCallback callback, object asyncState)
        {
            return new CompletedAsyncResult<string>(QueryWeatherFromRemoteSite(city));
        }

public string EndQueryWeather(IAsyncResult result)
        {
            return result.AsyncState as string;
        }

#endregion

static Task<string> QueryWeatherFromRemoteSite(string city)
        {
            //这里只是一个桩函数,表示的是一个异步方法
            return Task.FromResult("晴");
        }
    }

class CompletedAsyncResult<T> : IasyncResult
    {
        Task<T> task;
        ManualResetEvent waitHandle = new ManualResetEvent(false);

public CompletedAsyncResult(Task<T> task)
        {
            this.task = task;
            task.ContinueWith(_ => waitHandle.Set());
        }

#region IAsyncResult Members

public object AsyncState { get { return task.Result; } }
        public WaitHandle AsyncWaitHandle { get { return waitHandle; } }
        public bool CompletedSynchronously { get { return true; } }
        public bool IsCompleted { get { return task.IsCompleted; } }

#endregion
    }

编译运行后,从TestClient上来看,生成的接口并没有带上前面的Begin,从其发布的Wsdl来看,和之前的同步实现没有区别,也就是说:客户端是感知不到服务器端是如何实现的。

  

更加简单的异步实现:

从上面的实现来看,实现异步操作是要实现两个接口,BeginXXX和EndXXX,这个是非常麻烦的,在.Net 4.5里,我们可以通过async语法糖来简化这一过程。

首先还是来看看接口声明:

[ServiceContract]
    public interface IService1
    {
        [OperationContract]
        Task<string> QueryWeatherAsync(string city);
    }

和同步方式的契约声明也有两点区别:

  1. 返回值不是string,而是Task<string>
  2. 接口名称中加了Async后缀(这个其实不是必要的,但是为了良好的编程习惯,建议加上)。

既然接口就定义除了Task类型的返回值,那么实现就简单了:

public class Service1 : IService1
    {
        #region IService1 成员

public Task<string> QueryWeatherAsync(string city)
        {
            return QueryWeatherFromRemoteSite(city);
        }

#endregion

static Task<string> QueryWeatherFromRemoteSite(string city)
        {
            //这里只是一个桩函数,表示的是一个异步方法
            return Task.FromResult("晴");
        }
    }

比前面的BeginXXX的方式来说,简单且简洁了不少。

编译运行后,从TestClient上来看,生成的接口并没有带上结尾的Async,非常人性化。

  

三、小结:

在WCF架构中,服务器端不感知客户端以同步还是异步的方式来访问,客户端也感知不到服务器端是同步还是异步方式来实现服务的,这个也是一种松耦合的体现。

至于实现异步操作的实现:

    1. 客户端直接通过代码生成器可以同时生成异步步访问的接口,无需自己编写代码。
    2. 服务器端可以通过async和Task来简化异步接口的实现。

WCF异步调用的更多相关文章

  1. WCF 异步调用问题

    添加引用时生成"勾选允许生成异步操作" Wcf异步调用三种方式: 第一种:直接调用异步方法 var serviceClient = new MyServiceClient(); s ...

  2. 序列化和反序列化,异步调用web/wcf/函数

    //xml序列化 public static string Seria(DataSet ds) { XmlSerializer serializer = new XmlSerializer(typeo ...

  3. WCF初探-11:WCF客户端异步调用服务

    前言: 在上一篇WCF初探-10:WCF客户端调用服务 中,我详细介绍了WCF客户端调用服务的方法,但是,这些操作都是同步进行的.有时我们需要长时间处理应用程序并得到返回结果,但又不想影响程序后面代码 ...

  4. 如何实现异步调用WCF

    在面向服务的.NET开发中,我们经常要调用WCF服务加载数据,这时候,如果使用同步调用,会阻止UI,影响用户体验UE/UX,而且当服务器ping不通或者网速特别烂的情况下,这时候基本上是处于卡死状态, ...

  5. 多线程编程学习笔记——异步调用WCF服务

    接上文 多线程编程学习笔记——使用异步IO 接上文 多线程编程学习笔记——编写一个异步的HTTP服务器和客户端 接上文 多线程编程学习笔记——异步操作数据库 本示例描述了如何创建一个WCF服务,并宿主 ...

  6. WCF系列教程之客户端异步调用服务

    本文参考自http://www.cnblogs.com/wangweimutou/p/4409227.html,纯属读书笔记,加深记忆 一.简介 在前面的随笔中,详细的介绍了WCF客户端服务的调用方法 ...

  7. Prism for WPF 搭建一个简单的模块化开发框架(四)异步调用WCF服务、WCF消息头添加安全验证Token

    原文:Prism for WPF 搭建一个简单的模块化开发框架(四)异步调用WCF服务.WCF消息头添加安全验证Token 为什么选择wcf?   因为好像wcf和wpf就是哥俩,,, 为什么选择异步 ...

  8. 异步调用WCF的方法需要小心的地方

    直接使用下面的代码,由于client对象占用的资源没有被释放,会导致内存泄露GetSimServiceReference.GetSimServiceClient client = new GetSim ...

  9. WCF的异步调用

    1.服务契约 namespace Contracts { [ServiceContract] public interface ICalculator { [OperationContract] do ...

随机推荐

  1. capwap学习笔记——初识capwap(二)

    2.5.1 AC发现机制 WTP使用AC发现机制来得知哪些AC是可用的,决定最佳的AC来建立CAPWAP连接. WTP的发现过程是可选的.如果在WTP上静态配置了AC,那么WTP并不需要完成AC的发现 ...

  2. Twitter Lite以及大规模的高性能React渐进式网络应用

    Twitter Lite以及大规模的高性能React渐进式网络应用 原文:Twitter Lite and High Performance React Progressive Web Apps at ...

  3. ASP入门(七)-Response小案例

    我们通过ASP来创建一个年月日的选择框,年份从1950到2000年,如果手动输入HTML代码,其中的<option>列表项目要写94个 (51年 + 12月 + 31天),很是繁琐. 代码 ...

  4. nova network工作原理及配置

    1. nova network简介 网络管理和配置是云计算中一项非常重要的功能.nova自带的nova-network实现了一些基本的网络模型,允许虚拟机之间的相互通信及虚拟机对internet的访问 ...

  5. 面试总结——Java高级工程师(三)

    https://blog.csdn.net/moneyshi/article/details/53086927

  6. 使用Filter过滤非法内容

    1.首先,需要编写一个响应的封装器ResponseReplaceWrapper,用它来缓存response中的内容,代码如下: ResponseReplaceWrapper.java package ...

  7. 微信小程序 - debug(调试)

    微信小程序调试的方式是基于Chrome. 1. 常见console.log调试(可以具体参考console.log这个函数使用,它可不止这一个作用!) 2.使用NETWORK(我们可以查询到访问了那些 ...

  8. C++ 第九课 标准c数学函数

    abs() 求绝对值 acos() 求反余弦 asin() 求反正弦 atan() 求反正切 atan2() 求反正切,按符号判定象限 ceil() 求不小于某值的最小整数 (求上界) cos() 求 ...

  9. 高仿美团主界面&lt;一&gt;

    声明:本demo还未完好,正在持续更新中... 先上图吧: 这个小demo资源图片全是用青花瓷抠出来的,如今仅仅是完毕了 一部分. 会持续更行中. . .有兴趣的朋友能够关注我,我们一起coding, ...

  10. 用Java位运算实现加减乘除四则运算

    转载请注明原文地址:http://www.cnblogs.com/ygj0930/p/6412875.html 感谢博客:http://blog.csdn.net/itismelzp/article/ ...