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(3000);
            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, 0, (int)fileStream.Length);
                return bytes; 
            }
        }
    }
}
View Code

相关文章:

  • 2021-11-06
  • 2021-06-29
  • 2021-06-28
  • 2021-06-09
  • 2021-09-21
  • 2021-04-20
猜你喜欢
  • 2022-12-23
  • 2022-12-23
  • 2022-12-23
  • 2021-07-28
  • 2021-10-28
  • 2022-12-23
  • 2021-06-11
相关资源
相似解决方案