05 WCF异步编程

  

一、服务设计最佳实践

  在设计之初,是否用异步,应该由客户端来决定,而不应该去考虑服务的调用者调用的方式。

  

  优点:充分利用多核CPU,

     改善用户体验

  缺点:滥用异步,会影响性能

二、实现异步的方式

  WCF有两种方式实现异步调用代理类:

第一种:【方式1】用svcutil生成异步功能的代理类:

  

  方式是在svcutil后添加参数 /async

svcutil /async http://localhost:5555/WCFService

    【方式二】

  右键服务引用--【配置服务引用】--在弹出框中,勾选【允许生成异步操作】

第二种: 在客户端修改服务接口,添加异步方法:

  在服务端的服务接口是:

    [ServiceContract]
public interface IService1
{
[OperationContract]
byte[] GetFile(string fileName);
}

  则在客户端的项目中重新定义一个接口IAsyncService1,使其继承服务端的接口IService1,并额外添加BeginXXX()和EndXXX()方法,具体如下所示:

namespace Keasy5.WCF.Asyn.ByHand.Client
{
interface IAsyncService1 : IService1
{
[OperationContract(AsyncPattern = true)]
IAsyncResult BeginGetFile(string fileName, AsyncCallback callback, object asyncState); byte[] EndGetFile(IAsyncResult asyncResult);
}
}

  

三、实现方式

  

方式一:在添加服务引用时或后,修改服务引用配置

 服务端的接口和实现类定义

  IServer.cs

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

  Server.cs 

    public class Service1 : IService1
{
public string GetData(string message)
{
System.Threading.Thread.Sleep();
return string.Format("You entered: {0}", message);
}
}

    具体的做法是:

  第一步:右键服务引用--【配置服务引用】--在弹出框中,勾选【允许生成异步操作】

第二步:客户端调用异步方法,有两种调用方式:

      【方式一】客户端使用使用自动生成的代理类中的BeginXXX()和EndXXX()

        private void button2_Click(object sender, EventArgs e)
{
Service1Client service1Client = new Service1Client();
service1Client.BeginGetData("自动生成的异步方法"
,doCallBack,
service1Client); DoAfterCallWCFServer(); } private void doCallBack(IAsyncResult asyncResult)
{
Service1Client client = (Service1Client) asyncResult.AsyncState;
string message = client.EndGetData(asyncResult); MessageBox.Show(message); } private Void DoAfterCallWCFServer()
{
MessageBox.Show("调用WCF后的后续操作!");
}

    【方式二:使用xxxCompleted事件/xxxAsync方法】

        private void button3_Click(object sender, EventArgs e)
{
Service1Client service1Client = new Service1Client();
service1Client.GetDataCompleted +=service1Client_GetDataCompleted;
service1Client.GetDataAsync("XXXCompleted/XXXAsync"); //开始异步调用 DoAfterCallWCFServer();
} private void service1Client_GetDataCompleted(object sender, GetDataCompletedEventArgs e)
{
MessageBox.Show(e.Result);
} private void DoAfterCallWCFServer()
{
MessageBox.Show("调用WCF后的后续操作!");
}

  源代码下载:

  链接: http://pan.baidu.com/s/1gd1PNO3 密码: qtel

方式二:在客户端修改服务接口,添加异步方法

  

  在客户端修改的服务接口,添加异步方法,

  在客户端决定采用异步方式调用的操作时,修改了客户端的服务契约接口,但并不影响服务端的契约定义,

  第一步:创建3个项目:

【1】类库项目Keasy5.WCF.Asyn.Contract,用于定义客户端和服务端共同的契约

   【2】WinForm项目Keasy5.WCF.Asyn.ByHand.Client,作为客户端;其引用类库项目Keasy5.WCF.Asyn.Contract

   【3】WCF服务库项目Keasy5.WCF.Asyn.WCFServer,其引用类库项目Keasy5.WCF.Asyn.Contract

  第二步:类库项目Keasy5.WCF.Asyn.ByHand.Client添加接口IServer:

IServer1.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.ServiceModel;
using System.Text; namespace Keasy5.WCF.Asyn.Contract
{
[ServiceContract]
public interface IService1
{
[OperationContract(Action = "", ReplyAction = "")]
byte[] GetFile(string fileName);
}
}

  第二步:WCF服务库项目Keasy5.WCF.Asyn.WCFServer添加一个类Server1,用于实现类库项目Keasy5.WCF.Asyn.Contract添加接口IServer1:

Server1.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.Text;
using System.IO; using Keasy5.WCF.Asyn.Contract; namespace Keasy5.WCF.Asyn.WCFServer
{
public class Service1 : IService1
{
public byte[] GetFile(string fileName)
{
string path = System.IO.Path.Combine(System.AppDomain.CurrentDomain.BaseDirectory, fileName);
using (FileStream fileStream = new FileStream(path, FileMode.OpenOrCreate, FileAccess.Read))
{
byte[] bytes = new byte[fileStream.Length]; fileStream.Read(bytes, , (int)fileStream.Length);
return bytes;
}
}
}
}

 第三步:在客户端修改服务接口,添加异步方法

在Keasy5.WCF.Asyn.ByHand.Client项目中添加一个接口IAsyncService1接口,并且其继承类库项目Keasy5.WCF.Asyn.Contract定义的接口IServer1

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ServiceModel;
using Keasy5.WCF.Asyn.Contract; namespace Keasy5.WCF.Asyn.ByHand.Client
{
[ServiceContract]
interface IAsyncService1 : IService1
{
[OperationContract(AsyncPattern = true, Action = "", ReplyAction = "") ]
IAsyncResult BeginGetFile(string fileName, AsyncCallback callback, object asyncState); byte[] EndGetFile(IAsyncResult asyncResult);
}
}

  

  第四步:客户端调用异步方法:

  【1】先在配置文件app.config中添加节点配置:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="BasicHttpBinding_IService1" />
</basicHttpBinding>
</bindings>
<client>
<endpoint address="http://localhost:8733/Design_Time_Addresses/Keasy5.WCF.Asyn.WCFServer/Service1/"
binding="basicHttpBinding"
bindingConfiguration="BasicHttpBinding_IService1"

contract="Keasy5.WCF.Asyn.ByHand.Client.IAsyncService1" name="basicHttpIService1" />
</client>
</system.serviceModel>
</configuration>

注意:节点的contract属性值是

Keasy5.WCF.Asyn.ByHand.Client.IAsyncService1

是客户端定义的接口IAsyncService1。

  【2】然后用管道工厂ChannelFactory<T>,创建服务管道调用服务:

        private void button1_Click(object sender, EventArgs e)
{
//使用通道工厂创建服务
ChannelFactory<IAsyncService1> channelFactory = new ChannelFactory<IAsyncService1>("basicHttpIService1");
IAsyncService1 asyncService1 = channelFactory.CreateChannel(); asyncService1.BeginGetFile(@"abc.jpg", DoGetFileCallBack, asyncService1);
} private void DoGetFileCallBack(IAsyncResult asyncResult)
{
IAsyncService1 asyncService1 = (IAsyncService1) asyncResult.AsyncState;
byte[] recievedBytes = asyncService1.EndGetFile(asyncResult); if (recievedBytes.Length > )
{
MemoryStream memoryStream = new MemoryStream(recievedBytes);
this.pictureBox1.Image = Image.FromStream(memoryStream);

  
          MessageBox.Show("异步调用服务的后续操作");
}
else
{
MessageBox.Show("无法获取图片信息");
}
}

注意:常见的异常和处理方法:

【1】当接口IAsyncService1没有添加[ServiceContract]特性,会出现如下异常:

在 ServiceModel 客户端配置部分中,找不到名称“basicHttpIService1”和
协定“Keasy5.WCF.Asyn.Contract.IService1”的终结点元素。
这可能是因为未找到应用程序的配置文件,
或者是因为客户端元素中找不到与此名称匹配的终结点元素。

解决方案:

  在IAsyncService1没有添加[ServiceContract]特性

【2】异常:

类型“Keasy5.WCF.Asyn.Contract.IService1”中的同步 OperationContract 方法“GetFile”与异步 OperationContract 方法“BeginGetFile”和“EndGetFile”匹配,
因为它们具有相同的操作名称“GetFile”。
当同步 OperationContract 方法与一对异步 OperationContract 方法匹配时,
这两个 OperationContracts 必须具有相同的“Action”属性值。
在此情况下,值是不同的。要解决此问题,请更改其中一个 OperationContracts 的“Action”属性以与另一个匹配。此外,更改其中一个方法的名称将阻止匹配。

解决方法:

IServer1的GetFile方法和

IAsyncSever1的BeginGetFile方法

都添加如下特性:Action = "", ReplyAction = ""

[OperationContract(Action = "", ReplyAction = "")]

使它们的方法签名一样。

 【3】异常:

在 ServiceModel 客户端配置部分中,找不到名称“basicHttpIService1”和
协定“Keasy5.WCF.Asyn.ByHand.Client.IAsyncService1”的终结点元素。
这可能是因为未找到应用程序的配置文件,或者是因为客户端元素中找不到与此名称匹配的终结点元素。

这是由于客户端配置文件端点(endpoint )的Contract值是服务端的接口类型IServer1,而不是客户端的接口类型IAsyncServer1;

错误的客户端配置:

    <client>
<endpoint address="http://localhost:8733/Design_Time_Addresses/Keasy5.WCF.Asyn.WCFServer/Service1/"
binding="basicHttpBinding"
bindingConfiguration="BasicHttpBinding_IService1"
contract="MyWCFService.IService1"
name="basicHttpIService1" />
</client>

应该修改为客户端的接口类型IAsyncServer1:contract="Keasy5.WCF.Asyn.ByHand.Client.IAsyncService1",下面是正确的配置:

    <client>
<endpoint address="http://localhost:8733/Design_Time_Addresses/Keasy5.WCF.Asyn.WCFServer/Service1/"
binding="basicHttpBinding"
bindingConfiguration="BasicHttpBinding_IService1"
contract="Keasy5.WCF.Asyn.ByHand.Client.IAsyncService1"
name="basicHttpIService1" />
</client>

源码下载:

链接: http://pan.baidu.com/s/1c0nIOLi%20 密码: d71x

【WCF--初入江湖】05 WCF异步编程的更多相关文章

  1. WCF学习笔记之事务编程

    WCF学习笔记之事务编程 一:WCF事务设置 事务提供一种机制将一个活动涉及的所有操作纳入到一个不可分割的执行单元: WCF通过System.ServiceModel.TransactionFlowA ...

  2. 异步编程系列第05章 Await究竟做了什么?

    p { display: block; margin: 3px 0 0 0; } --> 写在前面 在学异步,有位园友推荐了<async in C#5.0>,没找到中文版,恰巧也想提 ...

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

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

  4. 【05】js异步编程理解

    1.概念 同步:一个任务等待前一个任务结束,然后再执行,程序的执行顺序与任务的排列顺序是一致的.同步的.异步:每一个任务有一个或多个回调函数(callback),前一个任务结束后,不是执行后一个任务, ...

  5. 异步编程 In .NET

    概述 在之前写的一篇关于async和await的前世今生的文章之后,大家似乎在async和await提高网站处理能力方面还有一些疑问,博客园本身也做了不少的尝试.今天我们再来回答一下这个问题,同时我们 ...

  6. 异步编程 In .NET(转)

    转自:http://www.cnblogs.com/jesse2013/p/Asynchronous-Programming-In-DotNet.html 概述 在之前写的一篇关于async和awai ...

  7. 【转】异步编程 In .NET

    概述 在之前写的一篇关于async和await的前世今生的文章之后,大家似乎在async和await提高网站处理能力方面还有一些疑问,博客园本身也做了不少的尝试.今天我们再来回答一下这个问题,同时我们 ...

  8. 异步编程 In .NET(转载)

    概述 在之前写的一篇关于async和await的前世今生的文章之后,大家似乎在async和await提高网站处理能力方面还有一些疑问,博客园本身也做了不少的尝试.今天我们再来回答一下这个问题,同时我们 ...

  9. 使用 Async 和 Await 的异步编程(C# 和 Visual Basic)[msdn.microsoft.com]

    看到Microsoft官方一篇关于异步编程的文章,感觉挺好,不敢独享,分享给大家. 原文地址:https://msdn.microsoft.com/zh-cn/library/hh191443.asp ...

随机推荐

  1. UI3_UIViewController生命周期

    // // SecondViewController.h // UI3_UIViewController生命周期 // // Created by zhangxueming on 15/7/2. // ...

  2. Python中lambda表达式学习

    lambda只是一个表达式,函数体比def简单很多. lambda的主体是一个表达式,而不是一个代码块.仅仅能在lambda表达式中封装有限的逻辑进去. lambda表达式是起到一个函数速写的作用.允 ...

  3. 《锋利的jQuery》心得笔记--Two Sections

    第三章 1.    DOM操作(节点) 1)         查找节点可以查找元素节点和属性节点 2)         创建节点: (1)       创建元素节点 var addLi = $(“&l ...

  4. Linux实现的IEEE 802.q VLAN

    本文转载自: http://blog.chinaunix.net/uid-20786208-id-4291059.html Technorati 标签: Linux VLAN   ---------- ...

  5. 关于C++string的长度陷阱

    std::string s = ...; ..... assert(s.length() == strlen(s.c_str())); 一般认为这段代码是不会断言失败的,但是实际上这段代码可能是会断言 ...

  6. 枪击手机屏幕应用android源码

    这款是作者最新的一款应用源码,枪击手机屏幕应用源码,该应用源码比较完整的,应用目前已经上线了一些应用商店了,大家想更深入的了解,可以到一些应用商店下载吧,直接搜索相关的关键字就可以搜到了,或者在下面有 ...

  7. 【转】CSS实现兼容性的渐变背景(gradient)效果

    一.有点俗态的开场白 要是两年前,实现“兼容性的渐变效果”这个说法估计不会被提出来的,那个时候,说起渐变背景,想到的多半是IE的渐变滤镜,其他浏览器尚未支持,但是,在对CSS3支持日趋完善的今天,实现 ...

  8. Demo学习: Basic jQuery

    UniGUI是一套基于ExtJS的Delphi的WEB框架,它是使用ExtPascal来转化到ExtJS,ExtJS是一个跨浏览器的JavaScript库,因此UniGUI发布出来的程序可以在各种浏览 ...

  9. 解决DataSnap支持的Tcp长连接数受限的两种方法

    如何解决DataSnap支持的Tcp长连接数受限的问题? 方案一: 采用代理服务器方式,基本流程为: 1.客户先连接代理服务器:2.获取可用的服务器IP和端口:3.关闭与代理服务器之间的连接:4.建立 ...

  10. 在Centos7上安装漏洞扫描软件Nessus

    本文摘要:简单叙述了在Centos7上安装Nessus扫描器的过程   Nessus 是目前全世界最多人使用的系统漏洞扫描与分析软件,Nessus的用户界面是基于Web界面来访问Nessus漏洞扫描器 ...