Hinweis
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, sich anzumelden oder das Verzeichnis zu wechseln.
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, das Verzeichnis zu wechseln.
Die asynchrone Kommunikation mit einem XML-Webdienst basiert auf dem asynchronen Entwurfsmuster, das generell von Microsoft .NET Framework verwendet wird. Bevor Sie auf diese Details eingehen, sollten Sie jedoch wissen, dass ein XML-Webdienst nicht ausdrücklich für die Verarbeitung asynchroner Anforderungen programmiert sein muss, damit er asynchron aufgerufen werden kann. Die Proxyklasse, die Sie mit dem Web Services Description Language-Tool (Wsdl.exe) für den Client erstellen, erstellt automatisch Methoden für das asynchrone Aufrufen der XML-Webdienstmethode. Dies trifft auch zu, wenn nur eine synchrone Implementierung der XML-Webdienstmethode vorhanden ist.
.NET Framework-Entwurfsmuster für das asynchrone Aufrufen von Methoden
Das von .NET Framework festgelegte Entwurfsmuster für das asynchrone Aufrufen von Methoden setzt voraus, dass für jede synchrone Methode zwei asynchrone Methoden vorhanden sind. Für jede synchrone Methode gibt es eine asynchrone Begin-Methode und eine asynchrone End-Methode. Die Begin-Methode wird von einem Client aufgerufen, um den Methodenaufruf zu starten. Der Client weist die Methode also an, die Verarbeitung des Methodenaufrufs zu beginnen, die Steuerung jedoch unverzüglich wieder zurückzugeben. Die End-Methode wird vom Client aufgerufen, um die Ergebnisse der Verarbeitung zu erhalten, die vom Methodenaufruf des XML-Webdienstes durchgeführt wurde.
Wie erkennt ein Client, wann die End-Methode aufgerufen werden soll? Gemäß .NET Framework-Definition gibt es zwei Methoden, einen Client für die Bestimmung zu implementieren. Die erste Methode besteht darin, eine Rückruffunktion an die Begin-Methode zu übergeben, die dann aufgerufen wird, wenn die Methode die Verarbeitung beendet hat. Bei der zweiten Methode wird eine der Methoden der WaitHandle-Klasse verwendet, damit der Client den Abschluss der Methode abwartet. Wenn ein Client die zweite Methode implementiert und die Begin-Methode aufruft, entspricht der Rückgabetyp nicht dem von der XML-Webdienstmethode angegebenen Datentyp, sondern einem Typ, der die IAsyncResult-Schnittstelle implementiert. Die IAsyncResult-Schnittstelle enthält eine AsyncWaitHandle-Eigenschaft vom Typ WaitHandle. Diese implementiert Methoden, die das Warten auf die Signalisierung von Synchronisierungsobjekte mit Hilfe von WaitHandle.WaitOne, WaitAny und WaitAll unterstützen. Wenn ein Synchronisierungsobjekt signalisiert wird, ist dies ein Zeichen, dass Threads, die mit der angegebenen Ressource verknüpft sind, dann auf die Ressource zugreifen können. Wenn ein XML-Webdienstclient die wait-Methode verwendet, um lediglich eine XML-Webdienstmethode asynchron aufzurufen, kann er WaitOne aufrufen, um das Verarbeitungsende dieser XML-Webdienstmethode abzuwarten.
Beachten Sie unbedingt, dass die gesendeten und empfangenen SOAP-Meldungen unabhängig davon, welche der beiden Methoden ein Client für die asynchrone Kommunikation mit einem XML-Webdienst wählt, mit denen der synchronen Kommunikation identisch sind. Es wird also immer nur eine SOAP-Anforderung und SOAP-Antwort im Netzwerk gesendet und empfangen. Die Proxyklasse erreicht dies, indem sie die SOAP-Antwort mit Hilfe eines anderen Threads behandelt als dem, den der Client für den Aufruf der Begin-Methode verwendet hat. Der Client kann daher die Arbeit in seinem Thread fortsetzen, während die Proxyklasse den Empfang und die Verarbeitung der SOAP-Antwort erledigt.
Implementieren eines XML-Webdienstclients, der einen asynchronen Methodenaufruf durchführt
Die Infrastruktur, in der ein mit ASP.NET erstellter XML-Webdienstclient einen XML-Webdienst asynchron aufrufen kann, ist in .NET Framework und die Proxyklasse integriert, die mit dem Web Services Description Language-Tool (Wsdl.exe) erstellt wurde. Das Entwurfsmuster für den asynchronen Aufruf wird von .NET Framework definiert; die Proxyklasse bietet den Mechanismus für die asynchrone Kommunikation mit einer XML-Webdienstmethode. Wenn mit Wsdl.exe eine Proxyklasse für einen XML-Webdienst erstellt wird, werden für jede öffentliche XML-Webdienstmethode im XML-Webdienst drei Methoden erstellt. In der folgenden Tabelle werden diese drei Methoden beschrieben.
| Methodenname in Proxyklasse | Beschreibung |
|---|---|
| <Webdienstmethodenname> | Sendet synchron eine Meldung für die XML-Webdienstmethode, die den Namen <Webdienstmethodenname> hat. |
| Begin<Webdienstmethodenname> | Startet den asynchronen Meldungsaustausch mit einer XML-Webdienstmethode namens <Webdienstmethodenname>. |
| End<Webdienstmethodenname> | Beendet den asynchronen Meldungsaustausch mit einer XML-Webdienstmethode namens <Webdienstmethodenname>, indem die vollständige Meldung von der XML-Webdienstmethode abgerufen wird. |
Im folgenden Codebeispiel wird eine XML-Webdienstmethode dargestellt, deren Verarbeitung eine ziemlich lange Zeit beanspruchen könnte. Sie ist folglich ein gutes Beispiel für Situationen, in denen Sie Ihren XML-Webdienstclient für den asynchronen Aufruf der XML-Webdienstmethode einrichten sollten.
<%@ WebService Language="C#" Class="PrimeFactorizer" %>
using System;
using System.Collections;
using System.Web.Services;
class PrimeFactorizer {
[WebMethod]
public long[] Factorize(long factorizableNum){
ArrayList outList = new ArrayList();
long i = 0;
int j;
try{
long Check = factorizableNum;
//Go through every possible integer
//factor between 2 and factorizableNum / 2.
//Thus, for 21, check between 2 and 10.
for (i = 2; i < (factorizableNum / 2); i++){
while(Check % i == 0){
outList.Add(i);
Check = (Check/i);
}
}
//Double-check to see how many prime factors have been added.
//If none, add 1 and the number.
j = outList.Count;
if (j == 0) {
outList.Add(1);
outList.Add(factorizableNum);
}
j = outList.Count;
//Return the results and
//create an array to hold them.
long[] primeFactor = new long[j];
for (j = 0; j < outList.Count; j++){
//Pass the values one by one, making sure
//to convert them to type ulong.
primeFactor[j] = Convert.ToInt64(outList[j]);
}
return primeFactor;
}
catch (Exception) {
return null;
}
}
}
[Visual Basic]
<%@ WebService Class="PrimeFactorizer" Language="VB" %>
Imports System
Imports System.Collections
Imports System.Web.Services
Public Class PrimeFactorizer
<WebMethod> _
Public Function Factorize(factorizableNum As Long) As Long()
Dim outList As New ArrayList()
Dim i As Long = 0
Dim j As Integer
Try
Dim Check As Long = factorizableNum
'Go through every possible integer
'factor between 2 and factorizableNum / 2.
'Thus, for 21, check between 2 and 10.
For i = 2 To CLng(factorizableNum / 2) - 1
While Check Mod i = 0
outList.Add(i)
Check = CLng(Check / i)
End While
Next i
'Double-check to see how many prime factors have been added.
'If none, add 1 and the number.
j = outList.Count
If j = 0 Then
outList.Add(1)
outList.Add(factorizableNum)
End If
j = outList.Count
'Return the results and
'create an array to hold them.
Dim primeFactor(j - 1) As Long
For j = 0 To outList.Count - 1
'Pass the values one by one, making sure
'to convert them to type ulong.
primeFactor(j) = CLng(outList(j))
Next j
Return primeFactor
Catch
Return Nothing
End Try
End Function
End Class
Das folgende Codebeispiel stellt einen Teil der Proxyklasse dar, die von Wsdl.exe für die oben aufgeführte XML-Webdienstmethode erstellt wurde. Beachten Sie die Methoden BeginFactorize und EndFactorize, da sie für die asynchrone Kommunikation mit der XML-Webdienstmethode Factorize verwendet werden.
public class PrimeFactorizer : System.Web.Services.Protocols.SoapHttpClientProtocol {
public long[] Factorize(long factorizableNum) {
object[] results = this.Invoke("Factorize", new object[] {
factorizableNum});
return ((long[])(results[0]));
}
public System.IAsyncResult BeginFactorize(long factorizableNum, System.AsyncCallback callback, object asyncState) {
return this.BeginInvoke("Factorize", new object[] {
factorizableNum}, callback, asyncState);
}
public long[] EndFactorize(System.IAsyncResult asyncResult) {
object[] results = this.EndInvoke(asyncResult);
return ((long[])(results[0]));
}
}
Es gibt zwei Methoden für die asynchrone Kommunikation mit einer XML-Webdienstmethode. Das folgende Codebeispiel veranschaulicht die asynchrone Kommunikation mit einer XML-Webdienstmethode sowie die Verwendung einer Rückruffunktion, mit der die Ergebnisse von der XML-Webdienstmethode abgerufen werden.
using System;
using System.Runtime.Remoting.Messaging;
using MyFactorize;
class TestCallback
{
public static void Main(){
long factorizableNum = 12345;
PrimeFactorizer pf = new PrimeFactorizer();
//Instantiate an AsyncCallback delegate to use as a parameter
//in the BeginFactorize method.
AsyncCallback cb = new AsyncCallback(TestCallback.FactorizeCallback);
// Begin the Async call to Factorize, passing in our
// AsyncCalback delegate and a reference
// to our instance of PrimeFactorizer.
IAsyncResult ar = pf.BeginFactorize(factorizableNum, cb, pf);
// Keep track of the time it takes to complete the async call
// as the call proceeds.
int start = DateTime.Now.Second;
int currentSecond = start;
while (ar.IsCompleted == false){
if (currentSecond < DateTime.Now.Second) {
currentSecond = DateTime.Now.Second;
Console.WriteLine("Seconds Elapsed..." + (currentSecond - start).ToString() );
}
}
// Once the call has completed, you need a method to ensure the
// thread executing this Main function
// doesn't complete prior to the call-back function completing.
Console.Write("Press Enter to quit");
int quitchar = Console.Read();
}
// Set up a call-back function that is invoked by the proxy class
// when the asynchronous operation completes.
public static void FactorizeCallback(IAsyncResult ar)
{
// You passed in our instance of PrimeFactorizer in the third
// parameter to BeginFactorize, which is accessible in the
// AsyncState property.
PrimeFactorizer pf = (PrimeFactorizer) ar.AsyncState;
long[] results;
// Get the completed results.
results = pf.EndFactorize(ar);
//Output the results.
Console.Write("12345 factors into: ");
int j;
for (j = 0; j<results.Length;j++){
if (j == results.Length - 1)
Console.WriteLine(results[j]);
else
Console.Write(results[j] + ", ");
}
}
}
[Visual Basic]
Imports System
Imports System.Runtime.Remoting.Messaging
Imports MyFactorize
Public Class TestCallback
Public Shared Sub Main()
Dim factorizableNum As Long = 12345
Dim pf As PrimeFactorizer = new PrimeFactorizer()
'Instantiate an AsyncCallback delegate to use as a parameter
' in the BeginFactorize method.
Dim cb as AsyncCallback
cb = new AsyncCallback(AddressOf TestCallback.FactorizeCallback)
' Begin the Async call to Factorize, passing in the
' AsyncCallback delegate and a reference to our instance
' of PrimeFactorizer.
Dim ar As IAsyncResult = pf.BeginFactorize(factorizableNum, _
cb, pf)
' Keep track of the time it takes to complete the async call as
' the call proceeds.
Dim start As Integer = DateTime.Now.Second
Dim currentSecond As Integer = start
Do while (ar.IsCompleted = false)
If (currentSecond < DateTime.Now.Second) Then
currentSecond = DateTime.Now.Second
Console.WriteLine("Seconds Elapsed..." + (currentSecond - start).ToString() )
End If
Loop
' Once the call has completed, you need a method to ensure the
' thread executing this Main function
' doesn't complete prior to the callback function completing.
Console.Write("Press Enter to quit")
Dim quitchar As Integer = Console.Read()
End Sub
' Set up the call-back function that is invoked by the proxy
' class when the asynchronous operation completes.
Public Shared Sub FactorizeCallback(ar As IAsyncResult)
' You passed in the instance of PrimeFactorizer in the third
' parameter to BeginFactorize, which is accessible in the
' AsyncState property.
Dim pf As PrimeFactorizer = ar.AsyncState
Dim results() as Long
' Get the completed results.
results = pf.EndFactorize(ar)
'Output the results.
Console.Write("12345 factors into: ")
Dim j as Integer
For j = 0 To results.Length - 1
If j = (results.Length - 1) Then
Console.WriteLine(results(j) )
Else
Console.Write(results(j).ToString + ", ")
End If
Next j
End Sub
End Class
Im folgenden Codebeispiel wird die asynchrone Kommunikation mit einer XML-Webdienstmethode sowie die anschließende Verwendung eines Synchronisierungsobjekts veranschaulicht, mit dem das Verarbeitungsende abgewartet wird.
// -----------------------------------------------------------------------// Async Variation 2.
// Asynchronously invoke the Factorize method,
//without specifying a call back.
using System;
using System.Runtime.Remoting.Messaging;
// MyFactorize, is the name of the namespace in which the proxy class is
// a member of for this sample.
using MyFactorize;
class TestCallback
{
public static void Main(){
long factorizableNum = 12345;
PrimeFactorizer pf = new PrimeFactorizer();
// Begin the Async call to Factorize.
IAsyncResult ar = pf.BeginFactorize(factorizableNum, null, null);
// Wait for the asynchronous operation to complete.
ar.AsyncWaitHandle.WaitOne();
// Get the completed results.
long[] results;
results = pf.EndFactorize(ar);
//Output the results.
Console.Write("12345 factors into: ");
int j;
for (j = 0; j<results.Length;j++){
if (j == results.Length - 1)
Console.WriteLine(results[j]);
else
Console.Write(results[j] + ", ");
}
}
}
[Visual Basic]
Imports System
Imports System.Runtime.Remoting.Messaging
Imports MyFactorize ' Proxy class namespace
Public Class TestCallback
Public Shared Sub Main()
Dim factorizableNum As Long = 12345
Dim pf As PrimeFactorizer = new PrimeFactorizer()
' Begin the Async call to Factorize.
Dim ar As IAsyncResult = pf.BeginFactorize(factorizableNum, Nothing, Nothing)
' Wait for the asynchronous operation to complete.
ar.AsyncWaitHandle.WaitOne()
' Get the completed results.
Dim results() as Long
results = pf.EndFactorize(ar)
'Output the results.
Console.Write("12345 factors into: ")
Dim j as Integer
For j = 0 To results.Length - 1
If j = (results.Length - 1) Then
Console.WriteLine(results(j) )
Else
Console.Write(results(j).ToString + ", ")
End If
Next j
End Sub
End Class
Wenn FactorizeCallback eine kontextgebundene Klasse ist, die einen synchronisierten/Threadaffinitätskontext erfordert, sollten Sie beachten, dass der Rückruf über die Kontextverteilerinfrastruktur gesendet wird. Je nach Aufrufer kann der Rückruf also für derartige Kontexte asynchron ausgeführt werden. Dies entspricht genau der Semantik eines unidirektionalen Qualifizierers für Methodensignaturen. Das bedeutet, dass jeder derartige Methodenaufruf je nach Aufrufer synchron oder asynchron ausgeführt werden kann und dass der Aufrufer keine Annahmen zur Beendigung eines derartigen Aufrufs machen kann, wenn die Ausführungssteuerung an ihn zurückgegeben wird.
Außerdem wird durch Aufrufen von EndInvoke vor dem Abschluss der asynchronen Operation der Aufrufer gesperrt. Das Verhalten für einen weiteren Aufruf mit demselben AsyncResult ist nicht definiert.
Die Cancel-Methode entspricht einer Anforderung für den Abbruch der Methodenverarbeitung, nachdem das festgelegte Timeoutintervall verstrichen ist. Beachten Sie, dass diese Anforderung vom Client stammt und vom Server behandelt werden sollte. Der Client muss nicht unbedingt Vermutungen darüber anstellen, ob der Server die Verarbeitung der Methode gestoppt hat, nachdem er die Meldung erhalten hat, dass die Methodenverarbeitung abgebrochen wurde. Es wird empfohlen, den Client keine Ressourcen, wie Dateiobjekte, zerstören zu lassen, da diese vom Server möglicherweise noch verwendet werden. Die IsCompleted-Eigenschaft der IAsyncResult-Instanz wird auf true festgelegt, nachdem der Server die Verarbeitung beendet hat, und es werden keine vom Client zur Verfügung gestellten Ressourcen mehr verwendet. Der Client kann die Ressourcen also zuverlässig zerstören, nachdem die IsCompleted-Eigenschaft auf true festgelegt wurde.
Siehe auch
Erstellen von XML-Webdienstclients | Suchen von XML-Webdiensten | Erstellen von Clients für XML-Webdienste | Durchsuchen von vorhandenen mit ASP.NET erstellten XML-Webdiensten | Zugreifen auf XML-Webdienste aus einem Browser