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

服务端接口操作

[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. activemq 控制面板里的 Number Of Pending Messages、 Messages Enqueued、Messages Dequeued含

    Number Of Consumers  消费者 这个是消费者端的消费者数量 Number Of Pending Messages 等待消费的消息 这个是当前未出队列的数量.可以理解为总接收数-总出队 ...

  2. spring boot 启动找不到或无法加载主类

    转载:https://www.cnblogs.com/mrray1105/p/8137247.html 刚开始是往上面箭头指出的方向去找问题的原因,但是试了各种方法后问题还是没有解决,于是乎我把焦点转 ...

  3. ZH奶酪:CSS中限制span显示字数

    span中的文字是取出于数据库的,不确定文字的个数,由于排版的原因只想让span不超过6个字,如果超过只显示六个,当鼠标悬浮上去的时候tip显示全部内容 Step1.在span中添加title < ...

  4. 【树莓派】树莓派与XBMC及Kodi、LibreELEC插件(一)

    网上高人多. 高手在民间,饭桶在机关. 越用树莓派,越发现这玩意儿的潜力,我想,未来我们用它,可以做很多事情. 最近在看树莓派的应用场景,看到网上有人用它做电视盒子. 参考相关文章,简单实践了一下,整 ...

  5. 如何随机获取数据库不连续ID的数据?

    这个问题的来由是我朋友要为一网站实现一个标签云功能,和我交流后我给出了一个方案,在此略作记录,亦求拍砖. 大概需求这是样的: 在数据库有一张表A如下图: 其中id字段的值未必是连续的,现在我朋友要做的 ...

  6. Warning: Divide by zero.

    问题:如标题 解决方案:分母加上+eps   参考自:http://www.ilovematlab.cn/thread-43128-1-1.html

  7. 禁用系统的Ctrl+Alt+Left/Right(方向键)

    对于非常多工具,如IntelliJ IDE,Ctrl+Alt+Left/Right(方向键)是一个非常重要的快捷键,可是这个快捷键经常会被一些显示相关的附属应用给占用用于调整屏幕显示的朝向,有时候即使 ...

  8. Webwork【03】核心类 ServletDispatcher 的初始化

    1. Webwork 与 Xwork 搭建环境需要的的jar 为:webwork-core-1.0.jar,xwork-1.0.jar,搭建webwork 需要xwork 的jar呢?原因是这样的,W ...

  9. MySQL中 PK NN UQ BIN UN ZF AI 的意思

    PK   Belongs to primary key作为主键 NN   Not Null非空 UQ  Unique index不能重复 BIN  Is binary column存放二进制数据的列 ...

  10. 转 CentOS开启FTP及配置用户

    原文链接: http://www.centos.bz/2011/03/centos-install-vsftpd-ftp-server/ vsftpd作为FTP服务器,在Linux系统中是非常常用的. ...