Utilizzare un servizio Web Windows Communication Foundation (WCF)
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:
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 , TodoItem
gestito 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.143
IP . 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:
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
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 nomeTodoWCFService
. 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 comebinding
. Aggiungere il codice XML seguente all'elemento, sostituendo l'indirizzobindings
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.
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'indirizzo10.0.2.2
dell'emulatore viene invece indirizzato alocalhost
nel computer host tramite un proxy interno. Queste richieste proxy avranno127.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.143
IP 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.