Verwenden eines ASP.NET-Webdiensts (ASMX)

Beispiel herunterladen Das Beispiel herunterladen

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. Consumer 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 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 ein untergeordnetes Element des Body-Elements sein.

SOAP kann über viele Transportprotokolle ausgeführt werden, einschließlich HTTP, SMTP, TCP und UDP. Ein ASMX-Dienst kann jedoch nur über HTTP betrieben werden. Die Xamarin-Plattform unterstützt SOAP 1.1-Standardimplementierungen über HTTP, und dies schließt die Unterstützung für viele der Standardmäßigen ASMX-Dienstkonfigurationen ein.

Dieses Beispiel umfasst die mobilen Anwendungen, die auf physischen oder emulierten Geräten ausgeführt werden, sowie 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 und verhindert so die versehentliche Offenlegung vertraulicher Informationen. Da ATS in Apps, die für iOS 9 erstellt wurden, standardmäßig aktiviert ist, unterliegen alle Verbindungen den ATS-Sicherheitsanforderungen. Wenn Verbindungen diese Anforderungen nicht erfüllen, schlagen sie mit einer Ausnahme fehl. 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 Datei Info.plist 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 To-Do-Elements Ein xml serialisiertes TodoItem
EditTodoItem Aktualisieren eines To-Do-Elements Ein xml serialisiertes TodoItem
DeleteTodoItem Löschen eines To-Do-Elements Ein xml serialisiertes TodoItem

Weitere Informationen zum in der Anwendung verwendeten Datenmodell finden Sie unter Modellieren der Daten.

Erstellen des TodoService-Proxys

Eine Proxyklasse namens TodoServiceerweitert SoapHttpClientProtocol und stellt Methoden für die Kommunikation mit dem ASMX-Dienst über HTTP bereit. Der Proxy wird generiert, indem jedem plattformspezifischen Projekt in Visual Studio 2019 oder Visual Studio 2017 ein Webverweis hinzugefügt wird. Der Webverweis generiert Methoden und Ereignisse für jede Aktion, die im WSDL-Dokument (Web Services Description Language) des Diensts definiert ist.

Beispielsweise führt die GetTodoItems Dienstaktion zu einer GetTodoItemsAsync Methode und einem GetTodoItemsCompleted Ereignis im Proxy. Die generierte Methode verfügt über einen void-Rückgabetyp und ruft die GetTodoItems Aktion für die übergeordnete SoapHttpClientProtocol Klasse auf. Wenn die aufgerufene Methode eine Antwort vom Dienst empfängt, löst sie das GetTodoItemsCompleted -Ereignis aus und stellt die Antwortdaten innerhalb der -Eigenschaft des Ereignisses Result bereit.

Erstellen der ISoapService-Implementierung

Damit das freigegebene, plattformübergreifende Projekt mit dem Dienst funktioniert, definiert das Beispiel die ISoapService Schnittstelle, die dem asynchronen Programmiermodell der Aufgabe in C# folgt. Jede Plattform implementiert den ISoapService , um den plattformspezifischen Proxy verfügbar zu machen. Im Beispiel werden Objekte verwendet TaskCompletionSource , um den Proxy als asynchrone Taskschnittstelle verfügbar zu machen. Details zur Verwendung TaskCompletionSource finden Sie in den Implementierungen der einzelnen Aktionstypen in den folgenden Abschnitten.

Das Beispiel SoapService:

  1. Instanziiert den TodoService als instance auf Klassenebene
  2. Erstellt eine Auflistung namens Items zum Speichern von TodoItem Objekten.
  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 proxygenerierten TodoItem Typ 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 instance und legt jede Eigenschaft auf die identische Eigenschaft aus dem TodoItem instance fest.

Ebenso müssen Daten beim Abrufen aus dem Webdienst vom proxygenerierten TodoItem Typ in einen TodoItem instance konvertiert werden. Dies wird mit der FromASMXServiceTodoItem -Methode erreicht, 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 aus dem vom Proxy generierten TodoItem Typ ab und legt sie im neu erstellten TodoItem instance fest.

Abrufen von Daten

Die ISoapService -Schnittstelle erwartet, dass die RefreshDataAsync -Methode eine Task mit der Elementauflistung zurückgibt. Die TodoService.GetTodoItemsAsync 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. Dadurch können Sie eine gültige Sammlung an die Benutzeroberfläche zurückgeben.

Im folgenden Beispiel wird ein neues TaskCompletionSourceerstellt, beginnt den asynchronen Aufruf in der RefreshDataAsync -Methode und wartet auf das Task vom bereitgestellte TaskCompletionSource. Wenn der TodoService_GetTodoItemsCompleted Ereignishandler aufgerufen wird, füllt er die Items Auflistung auf und aktualisiert :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 sich um TodoItem ein neues oder aktualisiertes Element handelt, und ruft die entsprechende Methode für das todoService -Objekt auf. Die CreateTodoItemCompleted Ereignishandler und EditTodoItemCompleted sollten auch implementiert werden, damit Sie wissen, wann eine todoService Antwort vom ASMX-Dienst empfangen wurde (diese können in einem einzelnen Handler kombiniert werden, da sie denselben Vorgang ausführen). Im folgenden Beispiel werden die Schnittstellen- und Ereignishandlerimplementierungen sowie das -Objekt veranschaulicht, das TaskCompletionSource zum asynchronen Betrieb 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 eine 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

Zum Testen physischer oder emulierter Geräte mit einem lokal gehosteten Dienst müssen benutzerdefinierte IIS-Konfiguration, Endpunktadressen und Firewallregeln vorhanden sein. 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.