Практическое руководство. Асинхронный вызов операций службы WCF
В этой статье описывается, как клиент может получить доступ к операции службы асинхронно. Служба в этой статье реализует ICalculator
интерфейс. Клиент может асинхронно вызывать операции этого интерфейса с помощью управляемой событиями модели асинхронного вызова. (Дополнительные сведения об асинхронной модели асинхронного вызова на основе событий см. в разделе Многопоточное программирование с асинхронным шаблоном на основе событий). Пример реализации операции асинхронно в службе см. в статье "Практическое руководство. Реализация асинхронной операции службы". Дополнительные сведения об синхронных и асинхронных операциях см. в разделе "Синхронные и асинхронные операции".
Примечание.
Управляемая событиями модель асинхронных вызовов не поддерживается при использовании класса ChannelFactory<TChannel>. Сведения о выполнении асинхронных вызовов с помощью инструкций ChannelFactory<TChannel>см. в статье "Практическое руководство. Асинхронное вызовы с помощью фабрики каналов".
Процедура
Асинхронный вызов операций службы WCF
Запустите средство служебной программы метаданных ServiceModel (Svcutil.exe) вместе с
/async
/tcv:Version35
параметрами команд, как показано в следующей команде.svcutil /n:http://Microsoft.ServiceModel.Samples,Microsoft.ServiceModel.Samples http://localhost:8000/servicemodelsamples/service/mex /a /tcv:Version35
Это создает, помимо синхронных и стандартных асинхронных операций на основе делегатов, клиентский класс WCF, содержащий:
Две
<operationName>``Async
операции для использования с асинхронным вызовом на основе событий. Например:public void AddAsync(double n1, double n2) { this.AddAsync(n1, n2, null); } public void AddAsync(double n1, double n2, object userState) { if ((this.onBeginAddDelegate == null)) { this.onBeginAddDelegate = new BeginOperationDelegate(this.OnBeginAdd); } if ((this.onEndAddDelegate == null)) { this.onEndAddDelegate = new EndOperationDelegate(this.OnEndAdd); } if ((this.onAddCompletedDelegate == null)) { this.onAddCompletedDelegate = new System.Threading.SendOrPostCallback(this.OnAddCompleted); } base.InvokeAsync(this.onBeginAddDelegate, new object[] { n1, n2}, this.onEndAddDelegate, this.onAddCompletedDelegate, userState); }
Public Overloads Sub AddAsync(ByVal n1 As Double, ByVal n2 As Double) Me.AddAsync(n1, n2, Nothing) End Sub Public Overloads Sub AddAsync(ByVal n1 As Double, ByVal n2 As Double, ByVal userState As Object) If (Me.onBeginAddDelegate Is Nothing) Then Me.onBeginAddDelegate = AddressOf Me.OnBeginAdd End If If (Me.onEndAddDelegate Is Nothing) Then Me.onEndAddDelegate = AddressOf Me.OnEndAdd End If If (Me.onAddCompletedDelegate Is Nothing) Then Me.onAddCompletedDelegate = AddressOf Me.OnAddCompleted End If MyBase.InvokeAsync(Me.onBeginAddDelegate, New Object() {n1, n2}, Me.onEndAddDelegate, Me.onAddCompletedDelegate, userState) End Sub
Операция завершила события формы
<operationName>``Completed
для использования с асинхронным вызовом на основе событий. Например:public event System.EventHandler<AddCompletedEventArgs> AddCompleted;
Public Event AddCompleted As System.EventHandler(Of AddCompletedEventArgs)
System.EventArgs типы для каждой операции (формы
<operationName>``CompletedEventArgs
) для использования с асинхронным вызовом на основе событий. Например:[System.Diagnostics.DebuggerStepThroughAttribute()] [System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "3.0.0.0")] public partial class AddCompletedEventArgs : System.ComponentModel.AsyncCompletedEventArgs { private object[] results; public AddCompletedEventArgs(object[] results, System.Exception exception, bool cancelled, object userState) : base(exception, cancelled, userState) { this.results = results; } public double Result { get { base.RaiseExceptionIfNecessary(); return ((double)(this.results[0])); } } }
<System.Diagnostics.DebuggerStepThroughAttribute(), _ System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "3.0.0.0")> _ Partial Public Class AddCompletedEventArgs Inherits System.ComponentModel.AsyncCompletedEventArgs Private results() As Object Public Sub New(ByVal results() As Object, ByVal exception As System.Exception, ByVal cancelled As Boolean, ByVal userState As Object) MyBase.New(exception, cancelled, userState) Me.results = results End Sub Public ReadOnly Property Result() As Double Get MyBase.RaiseExceptionIfNecessary Return CType(Me.results(0),Double) End Get End Property End Class
В вызывающем приложении создайте метод обратного вызова, вызываемый после завершения асинхронной операции, как показано в следующем примере кода.
// Asynchronous callbacks for displaying results. static void AddCallback(object sender, AddCompletedEventArgs e) { Console.WriteLine("Add Result: {0}", e.Result); }
' Asynchronous callbacks for displaying results. Private Shared Sub AddCallback(ByVal sender As Object, ByVal e As AddCompletedEventArgs) Console.WriteLine("Add Result: {0}", e.Result) End Sub
Перед вызовом операции используйте новый универсальный System.EventHandler<TEventArgs> тип
<operationName>``EventArgs
для добавления метода обработчика (созданного на предыдущем шаге) в<operationName>``Completed
событие. Затем вызовите метод<operationName>``Async
. Например:// AddAsync double value1 = 100.00D; double value2 = 15.99D; client.AddCompleted += new EventHandler<AddCompletedEventArgs>(AddCallback); client.AddAsync(value1, value2); Console.WriteLine("Add({0},{1})", value1, value2);
' AddAsync Dim value1 As Double = 100 Dim value2 As Double = 15.99 AddHandler client.AddCompleted, AddressOf AddCallback client.AddAsync(value1, value2) Console.WriteLine("Add({0},{1})", value1, value2)
Пример
Примечание.
Согласно правилам разработки для асинхронной модели на основе событий, если возвращается несколько значений, одно значение возвращается как свойство Result
, а остальные возвращаются как свойства объекта EventArgs. Одним из результатов этого является то, что если клиент импортирует метаданные с использованием параметров асинхронных команд на основе событий и операция возвращает более одного значения, объект EventArgs по умолчанию возвращает одно значение как свойство Result
, а остальные являются свойствами объекта EventArgs. Если требуется получать объект сообщения как свойство Result
, чтобы возвращаемые значения были свойствами этого объекта, используйте параметр команды /messageContract
. При этом формируется сигнатура, которая возвращает ответное сообщение как свойство Result
объекта EventArgs. Все внутренние возвращаемые значения тогда будут свойствами объекта ответного сообщения.
using System;
namespace Microsoft.ServiceModel.Samples
{
// The service contract is defined in generatedClient.cs, generated from the service by the svcutil tool.
class Client
{
static void Main()
{
Console.WriteLine("Press <ENTER> to terminate client once the output is displayed.");
Console.WriteLine();
// Create a client
CalculatorClient client = new CalculatorClient();
// AddAsync
double value1 = 100.00D;
double value2 = 15.99D;
client.AddCompleted += new EventHandler<AddCompletedEventArgs>(AddCallback);
client.AddAsync(value1, value2);
Console.WriteLine("Add({0},{1})", value1, value2);
// SubtractAsync
value1 = 145.00D;
value2 = 76.54D;
client.SubtractCompleted += new EventHandler<SubtractCompletedEventArgs>(SubtractCallback);
client.SubtractAsync(value1, value2);
Console.WriteLine("Subtract({0},{1})", value1, value2);
// Multiply
value1 = 9.00D;
value2 = 81.25D;
double result = client.Multiply(value1, value2);
Console.WriteLine("Multiply({0},{1}) = {2}", value1, value2, result);
// Divide
value1 = 22.00D;
value2 = 7.00D;
result = client.Divide(value1, value2);
Console.WriteLine("Divide({0},{1}) = {2}", value1, value2, result);
Console.ReadLine();
//Closing the client gracefully closes the connection and cleans up resources
client.Close();
}
// Asynchronous callbacks for displaying results.
static void AddCallback(object sender, AddCompletedEventArgs e)
{
Console.WriteLine("Add Result: {0}", e.Result);
}
static void SubtractCallback(object sender, SubtractCompletedEventArgs e)
{
Console.WriteLine("Subtract Result: {0}", e.Result);
}
}
}
Namespace Microsoft.ServiceModel.Samples
' The service contract is defined in generatedClient.vb, generated from the service by the svcutil tool.
Class Client
Public Shared Sub Main()
Console.WriteLine("Press <ENTER> to terminate client once the output is displayed.")
Console.WriteLine()
' Create a client
Dim client As New CalculatorClient()
' AddAsync
Dim value1 As Double = 100
Dim value2 As Double = 15.99
AddHandler client.AddCompleted, AddressOf AddCallback
client.AddAsync(value1, value2)
Console.WriteLine("Add({0},{1})", value1, value2)
' SubtractAsync
value1 = 145
value2 = 76.54
AddHandler client.SubtractCompleted, AddressOf SubtractCallback
client.SubtractAsync(value1, value2)
Console.WriteLine("Subtract({0},{1})", value1, value2)
' Multiply
value1 = 9
value2 = 81.25
Dim result As Double = client.Multiply(value1, value2)
Console.WriteLine("Multiply({0},{1}) = {2}", value1, value2, result)
' Divide
value1 = 22
value2 = 7
result = client.Divide(value1, value2)
Console.WriteLine("Divide({0},{1}) = {2}", value1, value2, result)
Console.ReadLine()
'Closing the client gracefully closes the connection and cleans up resources
client.Close()
End Sub
' Asynchronous callbacks for displaying results.
Private Shared Sub AddCallback(ByVal sender As Object, ByVal e As AddCompletedEventArgs)
Console.WriteLine("Add Result: {0}", e.Result)
End Sub
Private Shared Sub SubtractCallback(ByVal sender As Object, ByVal e As SubtractCompletedEventArgs)
Console.WriteLine("Subtract Result: {0}", e.Result)
End Sub
End Class
End Namespace