Verwenden eines ASP.NET-Webdiensts (ASMX)
ASMX bietet die Möglichkeit, Webdienste zu erstellen, die Nachrichten mithilfe des Simple Object Access Protocol (SOAP) senden. SOAP ist ein plattformunabhängiges und sprachunabhängiges Protokoll zum Erstellen und Zugreifen auf Webdienste. Verbraucher eines ASMX-Diensts müssen nichts über die Plattform, das Objektmodell oder die Programmiersprache wissen, die zum Implementieren des Diensts verwendet wird. Sie müssen nur verstehen, wie SOAP-Nachrichten gesendet und empfangen werden. In diesem Artikel wird veranschaulicht, wie Sie einen ASMX-SOAP-Dienst aus einer Xamarin.Forms Anwendung nutzen.
Eine SOAP-Nachricht ist ein XML-Dokument, das die folgenden Elemente enthält:
- Ein Stammelement namens Envelope , das das XML-Dokument als SOAP-Nachricht identifiziert.
- Ein optionales Header-Element , das anwendungsspezifische Informationen wie Authentifizierungsdaten enthält. Wenn das Header-Element vorhanden ist, muss es sich um das erste untergeordnete Element des Envelope-Elements sein.
- Ein erforderliches Body-Element , das die SOAP-Nachricht enthält, die für den Empfänger vorgesehen ist.
- Ein optionales Fault-Element , das verwendet wird, um Fehlermeldungen anzuzeigen. Wenn das Fault-Element vorhanden ist, muss es sich um ein untergeordnetes Element des Body-Elements handelt.
SOAP kann über viele Transportprotokolle ausgeführt werden, einschließlich HTTP, SMTP, TCP und UDP. Ein ASMX-Dienst kann jedoch nur über HTTP ausgeführt werden. Die Xamarin-Plattform unterstützt standardmäßige SOAP 1.1-Implementierungen über HTTP. Dies umfasst unterstützung für viele der standardmäßigen ASMX-Dienstkonfigurationen.
Dieses Beispiel enthält die mobilen Anwendungen, die auf physischen oder emulierten Geräten ausgeführt werden, und einen ASMX-Dienst, der Methoden zum Abrufen, Hinzufügen, Bearbeiten und Löschen von Daten bereitstellt. Wenn die mobilen Anwendungen ausgeführt werden, stellen sie eine Verbindung mit dem lokal gehosteten ASMX-Dienst her, wie im folgenden Screenshot gezeigt:
Hinweis
In iOS 9 und höher erzwingt App Transport Security (ATS) sichere Verbindungen zwischen Internetressourcen (z. B. dem Back-End-Server der App) und der App, wodurch die versehentliche Offenlegung vertraulicher Informationen verhindert wird. Da ATS standardmäßig in Apps aktiviert ist, die für iOS 9 erstellt wurden, unterliegen alle Verbindungen den ATS-Sicherheitsanforderungen. Wenn Verbindungen diese Anforderungen nicht erfüllen, tritt ein Ausnahmefehler auf.
ATS kann deaktiviert werden, wenn es nicht möglich ist, das Protokoll und die HTTPS
sichere Kommunikation für Internetressourcen zu verwenden. Dies kann durch Aktualisieren der Info.plist-Datei der App erreicht werden. Weitere Informationen finden Sie unter App Transport Security.
Nutzen des Webdiensts
Der ASMX-Dienst stellt die folgenden Vorgänge bereit:
Vorgang | Beschreibung | Parameter |
---|---|---|
GetTodoItems | Abrufen einer Liste von To-Do-Elementen | |
CreateTodoItem | Erstellen eines neuen Aufgabenelements | Ein serialisiertes XML-TodoItem |
EditTodoItem | Aktualisieren eines To-Do-Elements | Ein serialisiertes XML-TodoItem |
DeleteTodoItem | Löschen eines To-Do-Elements | Ein serialisiertes XML-TodoItem |
Weitere Informationen zum in der Anwendung verwendeten Datenmodell finden Sie unter Modellieren der Daten.
Erstellen des TodoService-Proxys
Eine als "Proxyklasse" bezeichnete TodoService
Proxyklasse erweitert SoapHttpClientProtocol
und stellt Methoden für die Kommunikation mit dem ASMX-Dienst über HTTP bereit. Der Proxy wird durch Hinzufügen eines Webverweises zu jedem plattformspezifischen Projekt in Visual Studio 2019 oder Visual Studio 2017 generiert. Der Webverweis generiert Methoden und Ereignisse für jede Aktion, die im WSDL-Dokument (Web Services Description Language) des Diensts definiert ist.
Die Dienstaktion führt beispielsweise GetTodoItems
zu einer GetTodoItemsAsync
Methode und einem GetTodoItemsCompleted
Ereignis im Proxy. Die generierte Methode weist einen ungültigen Rückgabetyp auf und ruft die GetTodoItems
Aktion für die übergeordnete SoapHttpClientProtocol
Klasse auf. Wenn die aufgerufene Methode eine Antwort vom Dienst empfängt, wird das GetTodoItemsCompleted
Ereignis ausgelöst und die Antwortdaten innerhalb der Eigenschaft des Ereignisses Result
bereitgestellt.
Erstellen der ISoapService-Implementierung
Um das gemeinsam genutzte plattformübergreifende Projekt für die Arbeit mit dem Dienst zu aktivieren, definiert das Beispiel die ISoapService
Schnittstelle, die dem asynchronen Programmiermodell "Aufgabe" in C# folgt. Jede Plattform implementiert die ISoapService
Plattform, um den plattformspezifischen Proxy verfügbar zu machen. Im Beispiel werden TaskCompletionSource
Objekte verwendet, um den Proxy als asynchrone Aufgabenschnittstelle verfügbar zu machen. Details zur Verwendung TaskCompletionSource
finden Sie in den Implementierungen der einzelnen Aktionstypen in den folgenden Abschnitten.
SoapService
Beispiel:
- Instanziiert die
TodoService
Instanz auf Klassenebene - Erstellt eine Auflistung, die zum Speichern
TodoItem
von Objekten aufgerufen wirdItems
. - Gibt einen benutzerdefinierten Endpunkt für die optionale
Url
Eigenschaft für dieTodoService
public class SoapService : ISoapService
{
ASMXService.TodoService todoService;
public List<TodoItem> Items { get; private set; } = new List<TodoItem>();
public SoapService ()
{
todoService = new ASMXService.TodoService ();
todoService.Url = Constants.SoapUrl;
...
}
}
Erstellen von Datenübertragungsobjekten
Die Beispielanwendung verwendet die TodoItem
Klasse zum Modellieren von Daten. Um ein TodoItem
Element im Webdienst zu speichern, muss es zuerst in den generierten TodoItem
Proxytyp konvertiert werden. Dies wird durch die ToASMXServiceTodoItem
Methode erreicht, wie im folgenden Codebeispiel gezeigt:
ASMXService.TodoItem ToASMXServiceTodoItem (TodoItem item)
{
return new ASMXService.TodoItem {
ID = item.ID,
Name = item.Name,
Notes = item.Notes,
Done = item.Done
};
}
Diese Methode erstellt eine neue ASMService.TodoItem
Instanz und legt jede Eigenschaft auf die identische Eigenschaft aus der TodoItem
Instanz fest.
Wenn Daten aus dem Webdienst abgerufen werden, muss sie auch vom generierten TodoItem
Proxytyp in eine TodoItem
Instanz konvertiert werden. Dies erfolgt mit der FromASMXServiceTodoItem
Methode, wie im folgenden Codebeispiel gezeigt:
static TodoItem FromASMXServiceTodoItem (ASMXService.TodoItem item)
{
return new TodoItem {
ID = item.ID,
Name = item.Name,
Notes = item.Notes,
Done = item.Done
};
}
Diese Methode ruft die Daten vom generierten TodoItem
Proxytyp ab und legt sie in der neu erstellten TodoItem
Instanz fest.
Abrufen von Daten
Die ISoapService
Schnittstelle erwartet, dass die RefreshDataAsync
Methode eine Task
mit der Elementauflistung zurückgibt. TodoService.GetTodoItemsAsync
Die Methode gibt jedoch "void" zurück. Um das Schnittstellenmuster zu erfüllen, müssen Sie aufrufen GetTodoItemsAsync
, warten, bis das GetTodoItemsCompleted
Ereignis ausgelöst wird, und die Auflistung auffüllen. Auf diese Weise können Sie eine gültige Sammlung an die Benutzeroberfläche zurückgeben.
Das folgende Beispiel erstellt einen neuen TaskCompletionSource
, beginnt den asynchronen Aufruf in der RefreshDataAsync
Methode und wartet auf die Task
TaskCompletionSource
vom . Wenn der TodoService_GetTodoItemsCompleted
Ereignishandler aufgerufen wird, füllt er die Items
Auflistung auf und aktualisiert folgendes TaskCompletionSource
:
public class SoapService : ISoapService
{
TaskCompletionSource<bool> getRequestComplete = null;
...
public SoapService()
{
...
todoService.GetTodoItemsCompleted += TodoService_GetTodoItemsCompleted;
}
public async Task<List<TodoItem>> RefreshDataAsync()
{
getRequestComplete = new TaskCompletionSource<bool>();
todoService.GetTodoItemsAsync();
await getRequestComplete.Task;
return Items;
}
private void TodoService_GetTodoItemsCompleted(object sender, ASMXService.GetTodoItemsCompletedEventArgs e)
{
try
{
getRequestComplete = getRequestComplete ?? new TaskCompletionSource<bool>();
Items = new List<TodoItem>();
foreach (var item in e.Result)
{
Items.Add(FromASMXServiceTodoItem(item));
}
getRequestComplete?.TrySetResult(true);
}
catch (Exception ex)
{
Debug.WriteLine(@"\t\tERROR {0}", ex.Message);
}
}
...
}
Weitere Informationen finden Sie unter "Asynchrones Programmiermodell" und "TPL" und "Herkömmliche .NET Framework-asynchrone Programmierung".
Erstellen oder Bearbeiten von Daten
Wenn Sie Daten erstellen oder bearbeiten, müssen Sie die ISoapService.SaveTodoItemAsync
Methode implementieren. Diese Methode erkennt, ob es TodoItem
sich um ein neues oder aktualisiertes Element handelt, und ruft die entsprechende Methode für das todoService
Objekt auf. Die CreateTodoItemCompleted
Ereignishandler und EditTodoItemCompleted
Ereignishandler sollten ebenfalls implementiert werden, damit Sie wissen, wann die todoService
Antwort vom ASMX-Dienst empfangen wurde (diese können in einen einzelnen Handler kombiniert werden, da sie denselben Vorgang ausführen). Das folgende Beispiel veranschaulicht die Schnittstellen- und Ereignishandlerimplementierungen sowie das Objekt, das TaskCompletionSource
zum asynchronen Arbeiten verwendet wird:
public class SoapService : ISoapService
{
TaskCompletionSource<bool> saveRequestComplete = null;
...
public SoapService()
{
...
todoService.CreateTodoItemCompleted += TodoService_SaveTodoItemCompleted;
todoService.EditTodoItemCompleted += TodoService_SaveTodoItemCompleted;
}
public async Task SaveTodoItemAsync (TodoItem item, bool isNewItem = false)
{
try
{
var todoItem = ToASMXServiceTodoItem(item);
saveRequestComplete = new TaskCompletionSource<bool>();
if (isNewItem)
{
todoService.CreateTodoItemAsync(todoItem);
}
else
{
todoService.EditTodoItemAsync(todoItem);
}
await saveRequestComplete.Task;
}
catch (SoapException se)
{
Debug.WriteLine("\t\t{0}", se.Message);
}
catch (Exception ex)
{
Debug.WriteLine("\t\tERROR {0}", ex.Message);
}
}
private void TodoService_SaveTodoItemCompleted(object sender, System.ComponentModel.AsyncCompletedEventArgs e)
{
saveRequestComplete?.TrySetResult(true);
}
...
}
Löschen von Daten
Das Löschen von Daten erfordert eine ähnliche Implementierung. Definieren Sie einen TaskCompletionSource
, implementieren Sie einen Ereignishandler und die ISoapService.DeleteTodoItemAsync
Methode:
public class SoapService : ISoapService
{
TaskCompletionSource<bool> deleteRequestComplete = null;
...
public SoapService()
{
...
todoService.DeleteTodoItemCompleted += TodoService_DeleteTodoItemCompleted;
}
public async Task DeleteTodoItemAsync (string id)
{
try
{
deleteRequestComplete = new TaskCompletionSource<bool>();
todoService.DeleteTodoItemAsync(id);
await deleteRequestComplete.Task;
}
catch (SoapException se)
{
Debug.WriteLine("\t\t{0}", se.Message);
}
catch (Exception ex)
{
Debug.WriteLine("\t\tERROR {0}", ex.Message);
}
}
private void TodoService_DeleteTodoItemCompleted(object sender, System.ComponentModel.AsyncCompletedEventArgs e)
{
deleteRequestComplete?.TrySetResult(true);
}
...
}
Testen des Webdiensts
Das Testen physischer oder emulierter Geräte mit einem lokal gehosteten Dienst erfordert eine benutzerdefinierte IIS-Konfiguration, Endpunktadressen und Firewallregeln. Weitere Informationen zum Einrichten Ihrer Umgebung für Tests finden Sie unter "Konfigurieren des Remotezugriffs auf IIS Express". Der einzige Unterschied zwischen dem Testen von WCF und ASMX ist die Portnummer des TodoService.