同步和非同步作業
描述本機非同步實作和叫用,以及同步使用非同步訊息交換。
許多應用程式會以非同步方式呼叫方法,因為這樣可在方法呼叫執行時,讓應用程式繼續執行有用的工作。Windows Communication Foundation (WCF) 服務和用戶端會在兩個不同層級的應用程式中參與非同步作業呼叫,這樣可讓 WCF 應用程式有更大的彈性可最大化針對互動性所平衡的輸送量。
非同步作業的類型
WCF 中的所有服務合約 (不管其參數型別和傳回值) 都會使用 WCF 屬性,以指定用戶端和服務之間特定的訊息交換模式。WCF 也會自動將傳入和傳出訊息遞送至適當的服務作業或執行用戶端程式碼。
用戶端僅擁有服務合約,而這個服務合約會指定特定作業的訊息交換模式。 只要觀察到基礎訊息交換模式,用戶端便可以提供開發人員所選擇的程式設計模型。 同樣的,只要觀察到指定的訊息模式,服務便可以任何方式實作作業。
服務合約與服務或用戶端實作無關,而這樣的獨立性就允許在 WCF 應用程式中以下列形式進行非同步執行:
用戶端可以使用同步訊息交換,以非同步方式叫用要求/回應作業。
服務可以使用同步訊息交換,來以非同步方式實作要求/回應作業。
不管用戶端或服務的實作如何,訊息交換可以是單向。
建議的非同步案例
如果作業服務實作發出封鎖呼叫 (例如進行 I/O 工作),這時請在服務作業實作中使用非同步方法。 當您處於非同步作業實作中時,請嘗試呼叫非同步作業和方法,盡可能地延伸非同步呼叫路徑。 例如,從 BeginOperationOne()
內呼叫 BeginOperationTwo()
。
在下列情況中,在用戶端中使用非同步化方法或呼叫應用程式:
如果您是從中介層應用程式叫用作業。 如需詳細資訊這類案例的詳細資訊,請參閱中介層用戶端應用程式。
如果您是叫用 ASP.NET 頁面內的作業,請使用非同步頁面。
如果您是從任何為單一執行緒的應用程式叫用作業,例如 Windows Forms 或 Windows Presentation Foundation (WPF)。 使用事件架構非同步呼叫模型時,結果事件會在 UI 執行緒上引發,並將回應新增至應用程式中,而不需要您自己去處理多個執行緒。
一般而言,如果您在同步與非同步呼叫之間有選擇,請選擇非同步呼叫。
用戶端非同步叫用
WCF 用戶端應用程式可使用兩種非同步呼叫模型,這兩種模型均於Asynchronous Programming Design Patterns中描述:
使用事件的非同步作業。
使用 System.IAsyncResult 物件的非同步作業。
第一個方法是事件架構非同步模式,建議呼叫應用程式時採用此模式,因為它只需要新增事件處理常式接收回應的通知 -- 結果事件會自動在使用者介面執行緒上引發。 若要使用此方法,請使用 ServiceModel 中繼資料公用程式工具 (Svcutil.exe) 同時指定 /async 和 /tcv:Version35 命令選項,如下列範例所示。
svcutil https://localhost:8000/servicemodelsamples/service/mex /async /tcv:Version35
當完成時,Svcutil.exe 會產生 WCF 用戶端類別,其中的事件基礎結構能夠呼叫應用程式去實作與指派事件處理常式,以接收回應並採取適當的動作。 如需完整的範例,請參閱 HOW TO:以非同步方式呼叫 WCF 服務作業。
但是,事件架構非同步呼叫只能在 .NET Framework version 3.5 中使用。 此外,使用 System.ServiceModel.ChannelFactory 建立 WCF 用戶端通道時,即使在 .NET Framework 3.5 中,亦不支援此呼叫。 透過 WCF 用戶端通道物件,您必須使用 System.IAsyncResult 物件非同步的叫用您的作業。 若要使用此方法,請使用 ServiceModel 中繼資料公用程式工具 (Svcutil.exe) 指定 /async 命令選項,如下列範例所示。
svcutil https://localhost:8000/servicemodelsamples/service/mex /async
這會產生服務合約,其中的每個作業會模型化為其 AsyncPattern 屬性會設為 true 的 <Begin> 方法,和對應的 <End> 方法。 如需使用 ChannelFactory 的完整範例,請參閱 HOW TO:使用通道處理站以非同步方式呼叫作業。
無論何種情況下,即使是以同步方式實作服務,應用程式仍可以使用非同步方式叫用作業,而透過相同的方式,應用程式可以使用相同的模式,以非同步方式叫用本機同步方法。 實作作業的方式對用戶端來說並不重要;回應訊息送達時,其內容會分派至用戶端的非同步 <End> 方法,而用戶端便會擷取該資訊。
非同步作業實作
同樣地,可以使用 .NET Framework 非同步程式設計模式並使 <Begin> 方法的 AsyncPattern 屬性設定為 true,即可以非同步方式實作服務作業。 在此情況下,會使用和同步作業相同的形式,在中繼資料中公開非同步作業:非同步作業會公開為具有要求訊息和相關聯之回應訊息的單一作業。 用戶端程式設計模型接著就會做出選擇。 只要在叫用服務時發生要求/回應訊息交換,這些程式設計模型就會將此模式表示為同步作業或非同步作業。
一般而言,基於系統的非同步本質,您不應該相依於執行緒。 將資料傳遞至作業分派處理之各種階段最可靠的方式就是使用延伸模組。
如需範例,請參閱 HOW TO:實作非同步服務作業。
若不管在用戶端應用程式中呼叫合約作業的方式,而要定義以非同步方式執行的合約作業 X
:
使用模式 BeginOperation 和 EndOperation 定義兩種方法。
BeginOperation 方法包含用於作業的 in 和 ref 參數,並會傳回 IAsyncResult 型別。
EndOperation 方法包含 IAsyncResult 參數、out 和 ref 參數,並會傳回作業的傳回型別。
以下列方法為例:
int DoWork(string data, ref string inout, out string outonly)
Function DoWork(ByVal data As String, ByRef inout As String, _
out outonly As out) As Integer
若要建立非同步作業,這兩個方法將會:
[OperationContract(AsyncPattern=true)]
IAsyncResult BeginDoWork(string data,
ref string inout,
AsyncCallback callback,
object state);
int EndDoWork(ref string inout, out string outonly, IAsyncResult result);
<OperationContract(AsyncPattern := True)> _
Function BeginDoWork(ByVal data As String, _
ByRef inout As String, _
ByVal callback As AsyncCallback, _
ByVal state As Object) _
As IAsyncResult
Function EndDoWork(ByRef inout As String, _
ByRef outonly As String, _
ByVal result As IAsyncResult) _
As Integer
![]() |
---|
OperationContractAttribute 屬性只會套用至 BeginDoWork 方法。 產生的合約具有一個名為 DoWork 的 WSDL 作業。
|
單向訊息交換模式
您也可以建立非同步訊息交換模式,而在這個模式中,用戶端或服務可以不管另一端,以任何方向傳送單向作業 (這是 System.ServiceModel.OperationContractAttribute.IsOneWay 為 true 的作業,而且沒有相關聯的回應) (這會使用具有單向訊息的雙工訊息交換模式)。 在這個情況下,服務合約會指定單向訊息交換,這表示每一端都可在適當時,選擇是否要實作為非同步呼叫或實作。 一般來說,當合約為單向訊息交換時,就可以大量地同步化實作,因為一旦傳送訊息時,應用程式不會等待回覆就可繼續執行其他工作。
事件架構非同步用戶端和訊息合約
事件架構非同步模型的設計方針指出,如果傳回多個值,則其中一個值會傳回做為 Result 屬性,其他值則傳回做為 EventArgs 物件上的屬性。 這麼做的結果就是,如果用戶端使用事件架構非同步命令選項匯入中繼資料,且作業傳回多個值,則預設 EventArgs 物件會傳回一個值做為 Result 屬性,而其餘則做為 EventArgs 物件的屬性。
如果您要接收訊息物件做為 Result 屬性,並讓傳回的值做為該物件的屬性,則使用 /messageContract 命令選項。 這會產生一個簽章,此簽章會將回應訊息傳回做為 EventArgs 物件的 Result 屬性。 然後,所有的內部傳回值都成為回應訊息物件的屬性。