程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> 關於.NET >> WCF技術剖析之十一:異步操作在WCF中的應用(下篇)

WCF技術剖析之十一:異步操作在WCF中的應用(下篇)

編輯:關於.NET

說完了客戶端的異步服務調用(參閱WCF技術剖析之十一:異步操作在WCF中的應用(上篇)),我們在來談談服務端如何通過異步的方式為服務提供實現。在定義服務契約的時候,相信大家已經注意到了OperationContractAttribute特性具有一個bool類型的AsynPattern。該屬性可以將一個服務操作定義成異步實現模式,接下來的內容主要是著眼於介紹異步操作的定義和實現原理。

一、異步操作的定義和實現原理

實現WCF異步服務操作模式在編程上具有一些限制:異步服務操作是通過兩個配對的方法實現的,並且采用典型的異步操作命名方式:BeginXxx/EndXxx。兩個方法需要采用如下的簽名,指定了AsyncPattern屬性的OperationContractAttribute只需要應用到BeginXxx方法上面。

   1: [OperationContract(AsyncPattern = true)]
2: IAsyncResult BeginDoWork(parameters, AsyncCallback userCallback, object stateObject);
3: ReturnType EndDoWork(IAsyncResult asynResult);

比如下面兩段代碼可以看作相同的操作在同步和異步下的不同表現。

   1: [OperationContract]
2: double Add(double x, double y);
1: [OperationContract(AsyncPattern = true)]
2: IAsyncResult BeginAdd(double x, double y, AsyncCallback userCallback, object stateObject);
3: double EndAdd(IAsyncResult asynResult);

理解了異步操作的定義模式之後,我們來談談WCF異步操作實現的原理。WCF通過類型OperationDescription表示對服務操作的描述。如下面的代碼所示,OperationDescription具有3個重要的MemthodInfo類型的屬性成員:SyncMethod、BeginMethod和EndMethod,分別表示同步方法、異步開始和結束方法。以上面的代碼為例,如果采用SyncMethod表示Add方法,而BeginMethod和EndMethod對應於BeginAdd和EndAdd方法。

   1: public class OperationDescription
2: {
3:
4: public MethodInfo SyncMethod { get; set; }
5: public MethodInfo BeginMethod { get; set; }
6: public MethodInfo EndMethod { get; set; }
7: //其他成員
8: }

WCF通過OperationSelector選擇相應的操作,通過OperationInvoker執行被選擇操作對應的方法。所有的OperationInvoker都實現了接口System.ServiceModel.Dispatcher.IOperationInvoker。下面是IOperationInvoker基本的定義。Invoke和InvokeBegin/InvokeEnd代表對操作同步和異步執行,IsSynchronous表示當前操作是否是異步的,如果操作的AsyncPattern為true則表明是異步操作。

   1: public interface IOperationInvoker
2: {
3: object[] AllocateInputs();
4: object Invoke(object instance, object[] inputs, out object[] outputs);
5: IAsyncResult InvokeBegin(object instance, object[] inputs, AsyncCallback callback, object state);
6: object InvokeEnd(object instance, out object[] outputs, IAsyncResult result);
7: bool IsSynchronous { get; }
8: }

在WCF中定義了兩個典型的OperationInvoker:SyncOperationInvoker與AsyncOperationInvoker,它們分別用於同步操作和異步操作的執行。這兩個OperationINvoker均實現了IOperationInvoker接口,SyncOperationInvoker實現了Invoke方法,AsyncOperationInvoker實現了InvokeBegin和InvokeEnd

當通過OperationSelector和InstanceProvider選出正確的方法和得到相應的服務實例的時候,WCF根據操作的AsyncPattern選擇相應的OperationInvoker。如果是同步的則自然選擇SyncOperationInvoker,執行Invoke方法。Invoke方法會通過OperationDescription的SyncMethod屬性,得到同步操作方法的MethodInfo,采用反射的機制執行該方法;對於異步操作,則會調用AsyncOperationInvoker的InvokeBegin和InvokeEnd方法,InvokeBegin和InvokeEnd方法對應的MethodInfo通過OperationDescription的BeginMethod和EndMethod屬性獲得。得到相應的MethodInfo對象後,同樣通過反射調用服務實例。

二、如何創建異步服務

在了解了異步操作的定義和具體的實現原理之後,我們通過一個簡單的實例演示異步操作在WCF應用中的實現。本例子中,我們通過服務調用來讀取服務端的文件,在實現文件讀取操作的時候,采用異步文件讀取方式。

先來看看服務契約的定義。服務契約通過接口IFileReader定義,基於文件名的文件讀取操作以異步的方式定義在BeginRead和EndRead方法中。

   1: using System;
2: using System.ServiceModel;
3: namespace Artech.AsyncServices.Contracts
4: {
5: [ServiceContract(Namespace="http://www.artech.com/")]
6: public interface IFileReader
7: {
8: [OperationContract(AsyncPattern = true)]
9: IAsyncResult BeginRead(string fileName, AsyncCallback userCallback, object stateObject);
10:
11: string EndRead(IAsyncResult asynResult);
12: }
13: }

FileReader實現了契約契約,在BeginRead方法中,根據文件名稱創建FileStream對象,調用FileStream的BeginRead方法實現文件的異步讀取,並直接返回該方法的執行結果:一個IAsyncResult對象。在EndRead方法中,調用FileStream的EndRead讀取文件內容,並關閉FileStream對象。

   1: using System;
2: using System.Text;
3: using Artech.AsyncServices.Contracts;
4: using System.IO;
5: namespace Artech.AsyncServices.Services
6: {
7: public class FileReaderService : IFileReader
8: {
9: private const string baseLocation = @"E:\";
10: private FileStream _stream;
11: private byte[] _buffer;
12:
13: #region IFileReader Members
14:
15: public IAsyncResult BeginRead(string fileName, AsyncCallback userCallback, object stateObject)
16: {
17: this._stream = new FileStream(baseLocation + fileName, FileMode.Open, FileAccess.Read, FileShare.Read);
18: this._buffer = new byte[this._stream.Length];
19: return this._stream.BeginRead(this._buffer, 0, this._buffer.Length, userCallback, stateObject);
20: }
21:
22: public string EndRead(IAsyncResult ar)
23: {
24: this._stream.EndRead(ar);
25: this._stream.Close();
26: return Encoding.ASCII.GetString(this._buffer);
27: }
28:
29: #endregion
30: }
31: }

采用傳統的方式寄宿該服務,並發布元數據。在客戶端通過添加服務引用的方式生成相關的服務代理代碼和配置。你將會發現客戶端生成的服務契約和服務代理類中,會有一個唯一的操作Read。也就是說,不管服務采用同步模式還是異步模式實現,對客戶端的服務調用方式沒有任何影響,客戶端可以任意選擇相應的模式進行服務調用。

   1: namespace Clients.ServiceReferences
2: {
3: [ServiceContractAttribute(ConfigurationName= "ServiceReferences.IFileReader")]
4: public interface IFileReader
5: {
6: [OperationContractAttribute(Action = " http://www.artech.com/IFileReader/Read", ReplyAction = " http://www.artech.com/IFileReader/ReadResponse")]
7: string Read(string fileName);
8: }
9:
10: public partial class FileReaderClient : ClientBase<IFileReader>, IFileReader
11: {
12:
13: public string Read(string fileName)
14: {
15: return base.Channel.Read(fileName);
16: }
17: }
18: }

直接借助於生成的服務代理類FileReaderClient,服務調用的代碼就顯得很簡單了。

   1: using System;
2: using Clients.ServiceReferences;
3: namespace Clients
4: {
5: class Program
6: {
7: static void Main(string[] args)
8: {
9: using (FileReaderClient proxy = new FileReaderClient())
10: {
11: Console.WriteLine(proxy.Read("test.txt"));
12: }
13: Console.Read();
14: }
15: }
16: }
  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved