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:

Beispielanwendung

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 TodoServiceProxyklasse 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.

SoapServiceBeispiel:

  1. Instanziiert die TodoService Instanz auf Klassenebene
  2. Erstellt eine Auflistung, die zum Speichern TodoItem von Objekten aufgerufen wirdItems.
  3. Gibt einen benutzerdefinierten Endpunkt für die optionale Url Eigenschaft für die TodoService
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 TaskTaskCompletionSourcevom . 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.