Utilizzare un servizio Web Windows Communication Foundation (WCF)

Download Sample Scaricare l'esempio

WCF è il framework unificato di Microsoft per la creazione di applicazioni orientate ai servizi. Consente agli sviluppatori di creare applicazioni distribuite sicure, affidabili, transazioni e interoperabili. Questo articolo illustra come utilizzare un servizio SOAP (Simple Object Access Protocol) WCF da un'applicazione Xamarin.Forms .

WCF descrive un servizio con diversi contratti, tra cui:

  • Contratti dati: definire le strutture di dati che costituiscono la base per il contenuto all'interno di un messaggio.
  • Contratti di messaggio: comporre messaggi da contratti dati esistenti.
  • Contratti di errore: consente di specificare errori SOAP personalizzati.
  • Contratti di servizio: specificare le operazioni supportate dai servizi e i messaggi necessari per interagire con ogni operazione. Specificano anche qualsiasi comportamento di errore personalizzato che può essere associato alle operazioni in ogni servizio.

Esistono differenze tra ASP.NET Servizi Web (ASMX) e WCF, ma WCF supporta le stesse funzionalità offerte da ASMX, ovvero messaggi SOAP su HTTP. Per altre informazioni sull'utilizzo di un servizio ASMX, vedere Utilizzare ASP.NET Servizi Web (ASMX).

Importante

Il supporto della piattaforma Xamarin per WCF è limitato ai messaggi SOAP codificati in testo su HTTP/HTTPS usando la BasicHttpBinding classe .

Il supporto wcf richiede l'uso di strumenti disponibili solo in un ambiente Windows per generare il proxy e ospitare TodoWCFService. La compilazione e il test dell'app iOS richiederanno la distribuzione di TodoWCFService in un computer Windows o come servizio Web di Azure.

Le app native di Xamarin Forms condividono in genere codice con una libreria di classi .NET Standard. Tuttavia, .NET Core attualmente non supporta WCF, pertanto il progetto condiviso deve essere una libreria di classi portabile legacy. Per informazioni sul supporto di WCF in .NET Core, vedere Scelta tra .NET Core e .NET Framework per le app server.

La soluzione dell'applicazione di esempio include un servizio WCF che può essere eseguito localmente ed è illustrato nello screenshot seguente:

Sample Application

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

È necessario generare un proxy per utilizzare un servizio WCF, che consente all'applicazione di connettersi al servizio. Il proxy viene costruito utilizzando i metadati del servizio che definiscono i metodi e la configurazione del servizio associata. Questi metadati vengono esposti sotto forma di documento WSDL (Web Services Description Language) generato dal servizio Web. Il proxy può essere compilato usando il provider di riferimento del servizio Web WCF Microsoft in Visual Studio 2017 per aggiungere un riferimento al servizio Web a una libreria .NET Standard. Un'alternativa alla creazione del proxy tramite il provider di riferimento del servizio Web WCF Microsoft in Visual Studio 2017 consiste nell'usare lo strumento utilità metadati ServiceModel (svcutil.exe). Per altre informazioni, vedere ServiceModel Metadata Utility Tool (Svcutil.exe).For more information, see ServiceModel Metadata Utility Tool (Svcutil.exe).

Le classi proxy generate forniscono metodi per l'utilizzo dei servizi Web che usano il modello di progettazione APM (Asynchronous Programming Model). In questo modello, un'operazione asincrona viene implementata come due metodi denominati BeginOperationName e EndOperationName, che iniziano e terminano l'operazione asincrona.

Il metodo BeginOperationName avvia l'operazione asincrona e restituisce un oggetto che implementa l'interfaccia IAsyncResult . Dopo aver chiamato BeginOperationName, un'applicazione può continuare a eseguire istruzioni sul thread chiamante, mentre l'operazione asincrona viene eseguita su un thread del pool di thread.

Per ogni chiamata a BeginOperationName, l'applicazione deve anche chiamare EndOperationName per ottenere i risultati dell'operazione. Il valore restituito di EndOperationName è lo stesso tipo restituito dal metodo del servizio Web sincrono. Ad esempio, il EndGetTodoItems metodo restituisce una raccolta di TodoItem istanze. Il metodo EndOperationName include anche un IAsyncResult parametro che deve essere impostato sull'istanza restituita dalla chiamata corrispondente al metodo BeginOperationName .

La libreria TPL (Task Parallel Library) può semplificare il processo di utilizzo di una coppia di metodi di inizio/fine APM incapsulando le operazioni asincrone nello stesso Task oggetto. Questo incapsulamento viene fornito da più overload del TaskFactory.FromAsync metodo.

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

Creare l'oggetto TodoServiceClient

La classe proxy generata fornisce la TodoServiceClient classe , usata per comunicare con il servizio WCF tramite HTTP. Fornisce funzionalità per richiamare i metodi del servizio Web come operazioni asincrone da un'istanza del servizio identificata dall'URI. Per altre informazioni sulle operazioni asincrone, vedere Panoramica del supporto asincrono.

L'istanza TodoServiceClient viene dichiarata a livello di classe in modo che l'oggetto si trovi fino a quando l'applicazione deve utilizzare il servizio WCF, come illustrato nell'esempio di codice seguente:

public class SoapService : ISoapService
{
  ITodoService todoService;
  ...

  public SoapService ()
  {
    todoService = new TodoServiceClient (
      new BasicHttpBinding (),
      new EndpointAddress (Constants.SoapUrl));
  }
  ...
}

L'istanza TodoServiceClient viene configurata con le informazioni di associazione e un indirizzo endpoint. Un'associazione viene usata per specificare i dettagli del trasporto, della codifica e del protocollo necessari per comunicare tra applicazioni e servizi. BasicHttpBinding Specifica che i messaggi SOAP codificati in testo verranno inviati tramite il protocollo di trasporto HTTP. Se si specifica un indirizzo endpoint, l'applicazione può connettersi a istanze diverse del servizio WCF, purché siano presenti più istanze pubblicate.

Per altre informazioni sulla configurazione del riferimento al servizio, vedere Configurazione del riferimento al servizio.

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 ToWCFServiceTodoItem metodo , come illustrato nell'esempio di codice seguente:

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

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

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 FromWCFServiceTodoItem metodo , come illustrato nell'esempio di codice seguente:

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

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

Recupero dei dati

I TodoServiceClient.BeginGetTodoItems metodi e TodoServiceClient.EndGetTodoItems vengono usati per chiamare l'operazione GetTodoItems fornita dal servizio Web. Questi metodi asincroni vengono incapsulati in un Task oggetto , come illustrato nell'esempio di codice seguente:

public async Task<List<TodoItem>> RefreshDataAsync ()
{
  ...
  var todoItems = await Task.Factory.FromAsync <ObservableCollection<TodoWCFService.TodoItem>> (
    todoService.BeginGetTodoItems,
    todoService.EndGetTodoItems,
    null,
    TaskCreationOptions.None);

  foreach (var item in todoItems)
  {
    Items.Add (FromWCFServiceTodoItem (item));
  }
  ...
}

Il Task.Factory.FromAsync metodo crea un Task oggetto che esegue il TodoServiceClient.EndGetTodoItems metodo al termine del TodoServiceClient.BeginGetTodoItems metodo, con il null parametro che indica che non viene passato alcun dato al BeginGetTodoItems delegato. Infine, il valore dell'enumerazione TaskCreationOptions specifica che deve essere utilizzato il comportamento predefinito per la creazione e l'esecuzione delle attività.

Il TodoServiceClient.EndGetTodoItems metodo restituisce un ObservableCollection di TodoWCFService.TodoItem istanze, che viene quindi convertito in un List di TodoItem istanze per la visualizzazione.

Crea flusso

I TodoServiceClient.BeginCreateTodoItem metodi e TodoServiceClient.EndCreateTodoItem vengono usati per chiamare l'operazione CreateTodoItem fornita dal servizio Web. Questi metodi asincroni vengono incapsulati in un Task oggetto , come illustrato nell'esempio di codice seguente:

public async Task SaveTodoItemAsync (TodoItem item, bool isNewItem = false)
{
  ...
  var todoItem = ToWCFServiceTodoItem (item);
  ...
  await Task.Factory.FromAsync (
    todoService.BeginCreateTodoItem,
    todoService.EndCreateTodoItem,
    todoItem,
    TaskCreationOptions.None);
  ...
}

Il Task.Factory.FromAsync metodo crea un oggetto Task che esegue il TodoServiceClient.EndCreateTodoItem metodo al termine del TodoServiceClient.BeginCreateTodoItem metodo, con il todoItem parametro passato al BeginCreateTodoItem delegato per specificare l'oggetto TodoItem da creare dal servizio Web. Infine, il valore dell'enumerazione TaskCreationOptions specifica che deve essere utilizzato il comportamento predefinito per la creazione e l'esecuzione delle attività.

Il servizio Web genera un'eccezione FaultException se non riesce a creare l'oggetto TodoItem, gestito dall'applicazione.

Aggiornamento dei dati

I TodoServiceClient.BeginEditTodoItem metodi e TodoServiceClient.EndEditTodoItem vengono usati per chiamare l'operazione EditTodoItem fornita dal servizio Web. Questi metodi asincroni vengono incapsulati in un Task oggetto , come illustrato nell'esempio di codice seguente:

public async Task SaveTodoItemAsync (TodoItem item, bool isNewItem = false)
{
  ...
  var todoItem = ToWCFServiceTodoItem (item);
  ...
  await Task.Factory.FromAsync (
    todoService.BeginEditTodoItem,
    todoService.EndEditTodoItem,
    todoItem,
    TaskCreationOptions.None);
  ...
}

Il Task.Factory.FromAsync metodo crea un Task oggetto che esegue il TodoServiceClient.EndEditTodoItem metodo al termine del TodoServiceClient.BeginCreateTodoItem metodo, con il todoItem parametro passato al BeginEditTodoItem delegato per specificare l'oggetto TodoItem da aggiornare dal servizio Web. Infine, il valore dell'enumerazione TaskCreationOptions specifica che deve essere utilizzato il comportamento predefinito per la creazione e l'esecuzione delle attività.

Il servizio Web genera un'eccezione FaultException se non riesce a individuare o aggiornare , TodoItemgestito dall'applicazione.

Eliminare dati

I TodoServiceClient.BeginDeleteTodoItem metodi e TodoServiceClient.EndDeleteTodoItem vengono usati per chiamare l'operazione DeleteTodoItem fornita dal servizio Web. Questi metodi asincroni vengono incapsulati in un Task oggetto , come illustrato nell'esempio di codice seguente:

public async Task DeleteTodoItemAsync (string id)
{
  ...
  await Task.Factory.FromAsync (
    todoService.BeginDeleteTodoItem,
    todoService.EndDeleteTodoItem,
    id,
    TaskCreationOptions.None);
  ...
}

Il Task.Factory.FromAsync metodo crea un Task oggetto che esegue il TodoServiceClient.EndDeleteTodoItem metodo al termine del TodoServiceClient.BeginDeleteTodoItem metodo, con il id parametro che viene passato al BeginDeleteTodoItem delegato per specificare l'oggetto TodoItem da eliminare dal servizio Web. Infine, il valore dell'enumerazione TaskCreationOptions specifica che deve essere utilizzato il comportamento predefinito per la creazione e l'esecuzione delle attività.

Il servizio Web genera un'eccezione FaultException se non riesce a individuare o eliminare l'oggetto TodoItem, gestito dall'applicazione.

Configurare l'accesso remoto a IIS Express

In Visual Studio 2017 o Visual Studio 2019 dovrebbe essere possibile testare l'applicazione UWP in un PC senza alcuna configurazione aggiuntiva. Il test dei client Android e iOS potrebbe richiedere i passaggi aggiuntivi descritti in questa sezione. Per altre informazioni, vedere Connessione ai servizi Web locali da simulatori iOS e emulatori Android.

Per impostazione predefinita, IIS Express risponderà solo alle richieste a localhost. I dispositivi remoti (ad esempio un dispositivo Android, un i Telefono o anche un simulatore) non avranno accesso al servizio WCF locale. Dovrai conoscere l'indirizzo IP della workstation Windows 10 nella rete locale. Ai fini di questo esempio, si supponga che la workstation abbia l'indirizzo 192.168.1.143IP . I passaggi seguenti illustrano come configurare Windows 10 e IIS Express per accettare connessioni remote e connettersi al servizio da un dispositivo fisico o virtuale:

  1. Aggiungere un'eccezione a Windows Firewall. È necessario aprire una porta tramite Windows Firewall che le applicazioni nella subnet possono usare per comunicare con il servizio WCF. Creare una regola in ingresso che apre la porta 49393 nel firewall. Da un prompt dei comandi amministrativo eseguire questo comando:

    netsh advfirewall firewall add rule name="TodoWCFService" dir=in protocol=tcp localport=49393 profile=private remoteip=localsubnet action=allow
    
  2. Configurare IIS Express per accettare connessioni remote. È possibile configurare IIS Express modificando il file di configurazione per IIS Express in [directory della soluzione].vs\config\applicationhost.config. Trovare l'elemento site con il nome TodoWCFService. Dovrebbe essere simile al codice XML seguente:

    <site name="TodoWCFService" id="2">
        <application path="/" applicationPool="Clr4IntegratedAppPool">
            <virtualDirectory path="/" physicalPath="C:\Users\tom\TodoWCF\TodoWCFService\TodoWCFService" />
        </application>
        <bindings>
            <binding protocol="http" bindingInformation="*:49393:localhost" />
        </bindings>
    </site>
    

    Sarà necessario aggiungere due binding elementi per aprire la porta 49393 all'esterno del traffico e l'emulatore Android. L'associazione usa un [IP address]:[port]:[hostname] formato che specifica il modo in cui IIS Express risponderà alle richieste. Le richieste esterne avranno nomi host che devono essere specificati come binding. Aggiungere il codice XML seguente all'elemento, sostituendo l'indirizzo bindings IP con il proprio indirizzo IP:

    <binding protocol="http" bindingInformation="*:49393:192.168.1.143" />
    <binding protocol="http" bindingInformation="*:49393:127.0.0.1" />
    

    Dopo aver modificato l'elemento bindings dovrebbe essere simile al seguente:

    <site name="TodoWCFService" id="2">
        <application path="/" applicationPool="Clr4IntegratedAppPool">
            <virtualDirectory path="/" physicalPath="C:\Users\tom\TodoWCF\TodoWCFService\TodoWCFService" />
        </application>
        <bindings>
            <binding protocol="http" bindingInformation="*:49393:localhost" />
            <binding protocol="http" bindingInformation="*:49393:192.168.1.143" />
            <binding protocol="http" bindingInformation="*:49393:127.0.0.1" />
        </bindings>
    </site>
    

    Importante

    Per impostazione predefinita, IIS Express non accetterà connessioni da origini esterne per motivi di sicurezza. Per abilitare le connessioni da dispositivi remoti, è necessario eseguire IIS Express con autorizzazioni Amministrazione istrative. Il modo più semplice per eseguire questa operazione consiste nell'eseguire Visual Studio 2017 con autorizzazioni Amministrazione istrative. Verrà avviato IIS Express con autorizzazioni Amministrazione istrative durante l'esecuzione di TodoWCFService.

    Al termine di questi passaggi, dovrebbe essere possibile eseguire TodoWCFService e connettersi da altri dispositivi nella subnet. È possibile testarlo eseguendo l'applicazione e visitando http://localhost:49393/TodoService.svc. Se viene visualizzato un errore di richiesta non valida quando si visita tale URL, bindings potrebbe non essere corretto nella configurazione di IIS Express (la richiesta raggiunge IIS Express ma viene rifiutata). Se viene visualizzato un errore diverso, è possibile che l'applicazione non sia in esecuzione o che il firewall non sia configurato correttamente.

    Per consentire a IIS Express di continuare l'esecuzione e la gestione del servizio, disattivare l'opzione Modifica e continuazione in Debugger Web > delle proprietà > del progetto.

  3. Personalizzare i dispositivi endpoint usati per accedere al servizio. Questo passaggio implica la configurazione dell'applicazione client, in esecuzione in un dispositivo fisico o emulato, per accedere al servizio WCF.

    L'emulatore Android usa un proxy interno che impedisce all'emulatore di accedere direttamente all'indirizzo del localhost computer host. L'indirizzo 10.0.2.2 dell'emulatore viene invece indirizzato a localhost nel computer host tramite un proxy interno. Queste richieste proxy avranno 127.0.0.1 come nome host nell'intestazione della richiesta, motivo per cui è stata creata l'associazione IIS Express per questo nome host nei passaggi precedenti.

    Il simulatore iOS viene eseguito in un host di compilazione Mac, anche se si usa il simulatore iOS remoto per Windows. Le richieste di rete dal simulatore avranno l'indirizzo IP della workstation nella rete locale come nome host (in questo esempio è , ma l'indirizzo 192.168.1.143IP effettivo sarà probabilmente diverso). Questo è il motivo per cui è stata creata l'associazione IIS Express per questo nome host nei passaggi precedenti.

    Assicurarsi che la SoapUrl proprietà nel file Constants.cs nel progetto TodoWCF (Portable) abbia valori corretti per la rete:

    public static string SoapUrl
    {
        get
        {
            var defaultUrl = "http://localhost:49393/TodoService.svc";
    
            if (Device.RuntimePlatform == Device.Android)
            {
                defaultUrl = "http://10.0.2.2:49393/TodoService.svc";
            }
            else if (Device.RuntimePlatform == Device.iOS)
            {
                defaultUrl = "http://192.168.1.143:49393/TodoService.svc";
            }
    
            return defaultUrl;
        }
    }
    

    Dopo aver configurato il Constants.cs con gli endpoint appropriati, dovrebbe essere possibile connettersi a TodoWCFService in esecuzione nella workstation Windows 10 da dispositivi fisici o virtuali.