Utilizzare un servizio Web ASP.NET (ASMX)

ASMX consente di creare servizi Web che inviano messaggi usando simple object access protocol (SOAP). SOAP è un protocollo indipendente dalla piattaforma e indipendente dal linguaggio per la creazione e l'accesso ai servizi Web. I consumer di un servizio ASMX non devono conoscere nulla sulla piattaforma, sul modello a oggetti o sul linguaggio di programmazione usato per implementare il servizio. Devono solo comprendere come inviare e ricevere messaggi SOAP. Questo articolo illustra come utilizzare un servizio SOAP ASMX da un'applicazione Xamarin.Forms .

Un messaggio SOAP è un documento XML contenente gli elementi seguenti:

  • Elemento radice denominato Envelope che identifica il documento XML come messaggio SOAP.
  • Elemento Header facoltativo che contiene informazioni specifiche dell'applicazione, ad esempio i dati di autenticazione. Se l'elemento Header è presente, deve essere il primo elemento figlio dell'elemento Envelope .
  • Elemento Body obbligatorio che contiene il messaggio SOAP destinato al destinatario.
  • Elemento Fault facoltativo usato per indicare i messaggi di errore. Se l'elemento Fault è presente, deve essere un elemento figlio dell'elemento Body .

SOAP può operare su molti protocolli di trasporto, tra cui HTTP, SMTP, TCP e UDP. Tuttavia, un servizio ASMX può funzionare solo su HTTP. La piattaforma Xamarin supporta implementazioni SOAP 1.1 standard su HTTP e include il supporto per molte delle configurazioni standard del servizio ASMX.

Questo esempio include le applicazioni per dispositivi mobili eseguite su dispositivi fisici o emulati e un servizio ASMX che fornisce metodi per ottenere, aggiungere, modificare ed eliminare dati. Quando le applicazioni per dispositivi mobili vengono eseguite, si connettono al servizio ASMX ospitato in locale, come illustrato nello screenshot seguente:

Applicazione di esempio

Nota

In iOS 9 e versioni successive, App Transport Security (ATS) applica connessioni sicure tra le risorse Internet (ad esempio il server back-end dell'app) e l'app, impedendo così la divulgazione accidentale di informazioni riservate. Poiché ATS è abilitato per impostazione predefinita nelle app compilate per iOS 9, tutte le connessioni saranno soggette ai requisiti di sicurezza di ATS. Se le connessioni non soddisfano questi requisiti, avranno esito negativo con un'eccezione. ATS può essere rifiutato esplicitamente se non è possibile usare il protocollo e proteggere la HTTPS comunicazione per le risorse Internet. A tale scopo, aggiornare il file Info.plist dell'app. Per altre informazioni, vedere App Transport Security.

Utilizzare il servizio Web

Il servizio ASMX fornisce le operazioni seguenti:

Operazione Descrizione Parametri
GetTodoItems Ottenere un elenco di elementi attività
CreateTodoItem Creare un nuovo elemento attività Oggetto TodoItem serializzato XML
EditTodoItem Aggiornare un elemento attività Oggetto TodoItem serializzato XML
DeleteTodoItem Eliminare un elemento attività Oggetto TodoItem serializzato XML

Per altre informazioni sul modello di dati usato nell'applicazione, vedere Modellazione dei dati.

Creare il proxy TodoService

Una classe proxy, denominata TodoService, estende SoapHttpClientProtocol e fornisce metodi per la comunicazione con il servizio ASMX tramite HTTP. Il proxy viene generato aggiungendo un riferimento Web a ogni progetto specifico della piattaforma in Visual Studio 2019 o Visual Studio 2017. Il riferimento Web genera metodi ed eventi per ogni azione definita nel documento WSDL (Web Services Description Language) del servizio.

Ad esempio, l'azione del GetTodoItems servizio genera un GetTodoItemsAsync metodo e un GetTodoItemsCompleted evento nel proxy. Il metodo generato ha un tipo restituito void e richiama l'azione GetTodoItems sulla classe padre SoapHttpClientProtocol . Quando il metodo richiamato riceve una risposta dal servizio, genera l'evento GetTodoItemsCompleted e fornisce i dati di risposta all'interno della proprietà dell'evento Result .

Creare l'implementazione di ISoapService

Per consentire il funzionamento del progetto multipiattaforma condiviso con il servizio, l'esempio definisce l'interfaccia ISoapService , che segue il modello di programmazione asincrona Attività in C#. Ogni piattaforma implementa per ISoapService esporre il proxy specifico della piattaforma. Nell'esempio vengono TaskCompletionSource usati oggetti per esporre il proxy come interfaccia asincrona dell'attività. I dettagli sull'uso TaskCompletionSource sono disponibili nelle implementazioni di ogni tipo di azione nelle sezioni seguenti.

SoapServiceEsempio:

  1. Crea un'istanza di TodoService come istanza a livello di classe
  2. Crea una raccolta denominata Items per archiviare TodoItem gli oggetti
  3. Specifica un endpoint personalizzato per la proprietà facoltativa Url nel 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;
        ...
    }
}

Creare oggetti di trasferimento dati

L'applicazione di esempio usa la TodoItem classe per modellare i dati. Per archiviare un TodoItem elemento nel servizio Web, è necessario prima convertirlo nel tipo generato dal TodoItem proxy. Questa operazione viene eseguita dal ToASMXServiceTodoItem metodo , come illustrato nell'esempio di codice seguente:

ASMXService.TodoItem ToASMXServiceTodoItem (TodoItem item)
{
    return new ASMXService.TodoItem {
        ID = item.ID,
        Name = item.Name,
        Notes = item.Notes,
        Done = item.Done
    };
}

Questo metodo crea una nuova ASMService.TodoItem istanza e imposta ogni proprietà sulla proprietà identica dall'istanza TodoItem di .

Analogamente, quando i dati vengono recuperati dal servizio Web, è necessario convertirli dal tipo generato TodoItem dal proxy a un'istanza TodoItem di . Questa operazione viene eseguita con il FromASMXServiceTodoItem metodo , come illustrato nell'esempio di codice seguente:

static TodoItem FromASMXServiceTodoItem (ASMXService.TodoItem item)
{
    return new TodoItem {
        ID = item.ID,
        Name = item.Name,
        Notes = item.Notes,
        Done = item.Done
    };
}

Questo metodo recupera i dati dal tipo generato TodoItem dal proxy e lo imposta nell'istanza appena creata TodoItem .

Recupero dei dati

L'interfaccia ISoapService prevede che il RefreshDataAsync metodo restituisca un Task oggetto con la raccolta di elementi. Tuttavia, il TodoService.GetTodoItemsAsync metodo restituisce void. Per soddisfare il modello di interfaccia, è necessario chiamare GetTodoItemsAsync, attendere che l'evento GetTodoItemsCompleted venga generato e popolare la raccolta. In questo modo è possibile restituire una raccolta valida all'interfaccia utente.

L'esempio seguente crea un nuovo TaskCompletionSourceoggetto , avvia la chiamata asincrona nel RefreshDataAsync metodo e attende l'oggetto Task fornito da TaskCompletionSource. Quando il TodoService_GetTodoItemsCompleted gestore eventi viene richiamato, popola la Items raccolta e aggiorna :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);
        }
    }

    ...
}

Per altre informazioni, vedere Modello di programmazione asincrona e TPL e Programmazione asincrona tradizionale di .NET Framework.

Creare o modificare i dati

Quando si creano o si modificano i dati, è necessario implementare il ISoapService.SaveTodoItemAsync metodo . Questo metodo rileva se TodoItem è un elemento nuovo o aggiornato e chiama il metodo appropriato sull'oggetto todoService . I CreateTodoItemCompleted gestori eventi e EditTodoItemCompleted devono essere implementati anche in modo da sapere quando ha todoService ricevuto una risposta dal servizio ASMX (questi possono essere combinati in un singolo gestore perché eseguono la stessa operazione). L'esempio seguente illustra le implementazioni dell'interfaccia e del gestore eventi, nonché l'oggetto TaskCompletionSource usato per operare in modo asincrono:

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);
    }

    ...
}

Eliminare dati

L'eliminazione dei dati richiede un'implementazione simile. Definire un TaskCompletionSource, implementare un gestore eventi e il ISoapService.DeleteTodoItemAsync metodo :

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);
    }

    ...
}

Testare il servizio Web

Per testare i dispositivi fisici o emulati con un servizio ospitato in locale, è necessario che siano presenti configurazioni IIS personalizzate, indirizzi endpoint e regole del firewall. Per altre informazioni su come configurare l'ambiente per i test, vedere Configurare l'accesso remoto a IIS Express. L'unica differenza tra il test di WCF e ASMX è il numero di porta di TodoService.