Usare le funzionalità di rete specifiche della piattaforma

Completato

HttpClient è un'implementazione gestita e quindi indipendente dallo stack di rete della piattaforma nativa. Di conseguenza, HttpClient non può usare le funzionalità di rete native di ogni piattaforma, che risulta perciò poco efficiente e meno ottimizzata.

In questa unità si sfrutta l'estendibilità di HttpClient e si aggiunge il supporto per lo stack di rete della piattaforma nativa.

Problemi con HttpClient

Per impostazione predefinita, HttpClient usa uno stack di rete gestito basato su interfacce di sistema operativo di livello base. Per questo motivo, HttpClient è indipendente dagli stack di rete in ogni piattaforma. Android e iOS hanno entrambi stack di rete nativi più efficienti, ma hanno anche API univoche che ne rendono più difficile l'uso da C#.

Di conseguenza, HttpClient non usa completamente la piattaforma nativa. Lo stack di rete nativo, ad esempio, quando la rete dati è disattivata, prova ad abilitarla automaticamente. Poiché HttpClient non usa lo stack di rete nativo per impostazione predefinita, non proverà ad attivarla.

Che cos'è un gestore di messaggi?

HttpClient è progettato per essere estendibile e supporta i gestori di messaggi per determinare la modalità di trasferimento delle informazioni e di gestione degli scenari HTTP comuni. Microsoft, ad esempio, ha creato un gestore di messaggi denominato HttpClientHandler. È possibile usarlo per personalizzare alcune funzionalità di HttpClient. Di seguito è riportato un esempio che mostra l'uso di HttpClientHandler:

var handler = new HttpClientHandler() {
   AllowAutoRedirect = false,
   UseProxy = true,
   AutomaticDecompression = DecompressionMethods.GZip,
   Credentials = new NetworkCredential("user", "passwd")
};

var client = new HttpClient(handler);

Come si può osservare, HttpClientHandler ha proprietà che è possibile impostare per personalizzare il comportamento di HttpClient. Per applicare le personalizzazioni a HttpClient, passarle nel costruttore.

Che cos'è NSUrlSessionHandler?

Xamarin.iOS include un gestore di messaggi denominato NSUrlSessionHandler, che fa in modo che HttpClient usi lo stack di rete nativo. NSUrlSessionHandler offre vantaggi come:

  • Attivazione automatica dell'opzione prima di avviare una richiesta.
  • Utilizzo del pool di connessioni iOS.
  • Uso di code di invio invece che di thread gestiti.

Il gestore permette a HttpClient di funzionare come un'applicazione nativa quando gestisce la rete.

Per impostare NSUrlSessionHandler, il codice è simile a quello dell'esempio seguente:

var client = new HttpClient(new NSUrlSessionHandler());

HttpClient ha ora i vantaggi dello stack di rete nativo.

Che cos'è AndroidClientHandler?

Proprio come Xamarin.iOS, Xamarin.Android include un gestore di messaggi chiamato AndroidClientHandler. AndroidClientHandler trasferisce l'attività di comunicazione di rete allo stack UrlConnection di Android. Questo gestore consente a HttpClient di usare qualsiasi protocollo di rete e i protocolli di crittografia che Android è in grado di gestire, ad esempio TLS 1.2.

Per impostare AndroidClientHandler, il codice è simile a quello dell'esempio seguente:

var client = new HttpClient(new AndroidClientHandler());

Quando usare NSUrlSessionHandler e AndroidClientHandler

Come regola generale, usare sempre NSUrlSessionHandler e AndroidClientHandler con HttpClient. Entrambi offrono i vantaggi dello stack di rete nativo.

Questi gestori vengono usati per impostazione predefinita nei nuovi progetti Xamarin.Forms. Esistono impostazioni del progetto per modificare il valore HttpClient predefinito.

Per modificare il gestore HttpClient predefinito per Xamarin.iOS, aprire le proprietà del progetto iOS. Nella scheda Compilazione iOS è disponibile l'opzione Implementazione di HttpClient. Se questa opzione viene impostata su NSUrlSession, HttpClient usa il gestore nativo per iOS senza passarlo al costruttore.

Per modificare il gestore HttpClient predefinito per Xamarin.Android, aprire le proprietà del progetto Android. Nella scheda Opzioni Android fare clic sul pulsante Avanzate in basso. Nella finestra di dialogo Opzioni Android avanzate è disponibile l'opzione Implementazione di SSL/TLS. Impostando questo valore su Native TLS 1.2+, HttpClient userà il gestore di messaggi predefinito.

Che cos'è App Transport Security?

Prima di concludere questa unità, c'è un'altra cosa da tenere presente quando si usa lo stack di rete nativo in iOS. App Transport Security (ATS) è una funzionalità che richiede che ogni comunicazione di rete eseguita attraverso lo stack di rete nativo usi TLS 1.2 o versione successiva. Gli algoritmi di crittografia moderni impediranno la divulgazione delle informazioni qualora una delle chiavi a lungo termine fosse compromessa.

Se l'app non osserva queste regole, le viene negato l'accesso alla rete. Se l'applicazione presenta questo problema, sono disponibili due opzioni. In primo luogo, è possibile modificare l'endpoint in modo che soddisfi i criteri di App Transport Security. In secondo luogo, è possibile rifiutare esplicitamente App Transport Security impostando alcune chiavi nel file Info.plist.

Rifiutare esplicitamente App Transport Security

Per rifiutare esplicitamente App Transport Security, aggiungere al file Info.plist una nuova chiave denominata NSAppTransportSecurity. In tale dizionario aggiungere un'altra chiave denominata NSExceptionDomains, che contiene un elemento figlio per ognuno degli endpoint di destinazione. Ecco un esempio di codice da aggiungere per rifiutare esplicitamente un endpoint:

<key>NSAppTransportSecurity</key>
<dict>
   <key>NSExceptionDomains</key>
      <dict>
      <key>dotnet.microsoft.com</key>
      <dict>
         <!-- specific options here -->
      </dict>
   </dict>
</dict>

In questo esempio è stata aggiunta all'endpoint un'eccezione in dotnet.microsoft.com. Se si esegue il debug di un servizio in locale nel computer di sviluppo, è possibile rifiutare esplicitamente il traffico locale con la chiave NSAllowsLocalNetworking.

<key>NSAppTransportSecurity</key>    
<dict>
    <key>NSAllowsLocalNetworking</key>
    <true/>
</dict>

Se infine non è possibile identificare tutti gli endpoint, disabilitare App Transport Security per tutti gli endpoint non specificati usando la chiave NSAllowsArbitraryLoads. Ecco un esempio nel codice:

<key>NSAppTransportSecurity</key>
<dict>
   <key>NSAllowsArbitraryLoads</key>
   <true/>
</dict>

Sono disponibili altre opzioni che possono essere aggiunte per specificare in modo più dettagliato la modalità del rifiuto esplicito. Queste indicazioni non rientrano nell'ambito di questo modulo. Le opzioni sono illustrate nella documentazione di Xamarin.iOS ATS.

Che cos'è Android Network Security Configuration?

Analogamente a iOS, Android ha un modello di sicurezza simile per le comunicazioni di rete, introdotto con Android 9 (livello API 28). Il traffico non crittografato (non HTTPS) viene disabilitato per impostazione predefinita quando l'applicazione viene eseguita in ed è destinata ad Android 9 (livello API 28) o superiore. Questo criterio può avere un effetto sul ciclo di sviluppo se l'app deve scaricare un'immagine o un file in un server che non è stato configurato per HTTPS. È inoltre possibile che si stia semplicemente provando a eseguire il debug dell'applicazione in locale e non si vogliano installare i certificati di sviluppo. È possibile che siano presenti requisiti aziendali sicuri che richiedono che tutto il traffico Web in tutte le versioni di Android sia sempre HTTPS. La nuova funzionalità Network Security Configuration di Android viene usata in questo scenario per semplificare l'ottimizzazione della sicurezza del traffico di rete nell'app.

Consentire il traffico non crittografato

Per consentire il traffico non crittografato, sarà necessario creare una configurazione di sicurezza di rete. Verrà creato prima di tutto un nuovo file XML in Resources/xml denominato network_security_config.xml. All'interno di questo file verrà aggiunto network-security-config con le impostazioni domain-config. La configurazione seguente consentirà il traffico non crittografato per un dominio specifico e per un indirizzo IP:

<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
  <domain-config cleartextTrafficPermitted="true">
    <domain includeSubdomains="true">10.0.2.2</domain> <!-- Debug port -->
    <domain includeSubdomains="true">xamarin.com</domain>
  </domain-config>
</network-security-config>

È possibile migliorare la sicurezza dell'app anche limitando il traffico non crittografato in tutte le versioni di Android, indipendentemente dal framework di compilazione e di destinazione. Questa operazione viene eseguita impostando cleartextTrafficPermitted su false. L'abilitazione di questa opzione consente di limitare qualsiasi traffico non HTTPS in qualsiasi momento.

L'ultima operazione da eseguire consiste nel configurare la proprietà networkSecurityConfig nel nodo application in AndroidManifest.xml presente nella cartella Proprietà:

<?xml version="1.0" encoding="utf-8"?>
<manifest>
    <application android:networkSecurityConfig="@xml/network_security_config">
        ...
    </application>
</manifest>

Sono disponibili altre opzioni che possono essere aggiunte per specificare in modo più dettagliato la modalità del rifiuto esplicito. Queste indicazioni non rientrano nell'ambito di questo modulo. Le opzioni sono descritte nella Guida alla configurazione della sicurezza di rete di Google.

Eseguire il debug di servizi e app in locale

Un vantaggio della creazione di applicazioni per dispositivi mobili con C# e .NET consiste infine nella possibilità di condividere il codice e la conoscenza con altre applicazioni .NET, ad esempio il back-end dell'API Web ASP.NET Core fornito qui. Le applicazioni per dispositivi mobili in esecuzione nel simulatore iOS o nell'emulatore Android possono inoltre usare servizi Web ASP.NET Core in esecuzione in locale ed esposti su HTTP, come indicato di seguito:

Le applicazioni in esecuzione nel simulatore iOS possono connettersi ai servizi Web HTTP locali tramite l'indirizzo IP del computer o tramite il nome host localhost. L'applicazione deve rifiutare esplicitamente ATS specificando almeno NSAllowsLocalNetworking. Ad esempio, dato un servizio Web HTTP locale che espone un'operazione GET tramite l'URI relativo /api/todoitems/, un'applicazione in esecuzione nel simulatore iOS può utilizzare l'operazione inviando una richiesta GET a http://localhost:<port>/api/todoitems/.

Le applicazioni in esecuzione nell'emulatore Android possono connettersi ai servizi Web HTTP locali tramite l'indirizzo 10.0.2.2, ovvero un alias per l'interfaccia di loopback host (127.0.0.1 nel computer di sviluppo). È necessario configurare anche una configurazione di sicurezza di rete per questo indirizzo IP specifico. Ad esempio, dato un servizio Web HTTP locale che espone un'operazione GET tramite l'URI relativo /api/todoitems/, un'applicazione in esecuzione nell'emulatore Android può utilizzare l'operazione inviando una richiesta GET a http://10.0.2.2:<port>/api/todoitems/.

I servizi Web ASP.NET Core devono disabilitare i reindirizzamenti HTTPS escludendo app.UseHttpsRedirection(); tramite commento nel file Startup.cs.

Rilevare il sistema operativo

La classe DeviceInfo può essere usata per rilevare la piattaforma su cui è esecuzione l'applicazione. Il nome host appropriato, che consente l'accesso ai servizi Web sicuri locali, può quindi essere impostato come segue.

public static string BaseAddress =
    DeviceInfo.Platform == DevicePlatform.Android ? "``http://10.0.2.2:5000``" : "``http://localhost:5000``";
public static string TodoItemsUrl = $"{BaseAddress}/api/todoitems/";

Per altre informazioni, vedere la documentazione Connettersi ai servizi Web locali.

Verifica le tue conoscenze

1.

Quale dei seguenti è il motivo migliore per usare gli stack di rete nativi con HttpClient?

2.

Quale delle seguenti opzioni non è un modo valido per rifiutare esplicitamente App Transport Security?