JSON for Dummies (parte 4)

Dopo aver visto come connetterci ad un servizio REST con HttpClient (vedi la parte 3) concludiamo l’argomento illustrando come connetterci ad un servizio REST autenticato e come eseguire altre operazioni che non siano solo il semplice GET.

Tutto quello che dobbiamo fare è semplicemente usare il costruttore dell’HttpClient che prende un oggetto HttpClientHandler come parametro e impostare la proprietà Credential di quest’ultimo uguale ad un oggetto NetworkCredential che possiamo passare alla nostra funzione

 NetworkCredential credential = new NetworkCredential(username, password); 

L’ultima cosa da modificare è DefaultRequestHeaders dell’HttpClient, e a questo punto la funzione che permette di fare una chiamata Get autenticata può essere scritta in questo modo:

  
public static async Task<T> GetAsyncAuthenticated<T>Uri uri, NetworkCredential credential) 
{
     using (var http = new HttpClient(new HttpClientHandler { Credentials = credential }))     
     {         
          http.DefaultRequestHeaders.Add"Accept", "application/json");
          http.DefaultRequestHeaders.Add("user-Agent", "authentication.cs");
          var response = await http.GetAsync(uri);
          string json = await response.EnsureSuccessStatusCode().Content.ReadAsStringAsync();
          var output = JsonConvert.DeserializeObject<T>(json);
          return output;
     } 
} 

In modo assolutamente analogo possiamo scrivere una funzione che esegua un POST autenticato (o non autenticato, basta rimuovere le parti relative all’autenticazione), dove ovviamente dobbiamo passare anche un content da passare al POST

 
public static async Task<T> PostAsyncAuthenticated<T>(Uri uri, NetworkCredential credential, HttpContent content)
{ 	
     using (var http = new HttpClient(new HttpClientHandler { Credentials = credential }))
     {                 
          http.DefaultRequestHeaders.Add("Accept", "application/json");
          http.DefaultRequestHeaders.Add"user-Agent", "authentication.cs");
          var response = await http.PostAsync(uri, content);                 
          string json = await response.EnsureSuccessStatusCode().Content.ReadAsStringAsync();                 
          return JsonConvert.DeserializeObject<T>(json); 	
     } 
} 

Come vedete usando HttpClient è tutto molto semplice. Buon lavoro!

Annunci

JSON for Dummies (parte 3)

In questo terzo post della serie JSON for Dummies (qui la parte 1 e la parte 2) vedremo una implementazione più elegante del processo di deserializzazione di dati JSON provenienti da un servizio REST.

Creeremo una funzione asincrona generica che si occupi di connettersi al servizio remoto, scaricare i dati e deserializzarli nel tipo corretto. La prima modifica è che useremo il metodo GetAsync() di HttpClient invece del metodo GetStringAsync(). In questo modo avremo una risposta del tipo HttpResponseMessage  che espone proprietà utili a stabilire l’esito della connessione. In questa prima implementazione Controlleremo che lo StatusCode della risposta sia positivo prima di continuare. In caso contrario lanceremo una eccezione. Dopo aver verificato l’esito positivo dell’operazione possiamo deserializzare il contenuto della risposta con ReadAsStringAsync().

public async Task<T> GetAsync<T> (Uri uri)
{
    using (var http = new HttpClient())
    {
         http.DefaultRequestHeaders.Add("Accept", "application/json");
         var response = await http.GetAsync(uri);
         if (response.StatusCode != System.Net.HttpStatusCode.OK)
         throw new Exception(response.StatusCode.ToString());
         string json = await response.Content.ReadAsStringAsync();
         return JsonConvert.DeserializeObject<T>(json);
    }
}

Grazie all’uso di HttpResponseMessage  possiamo rendere ulteriormente compatto il codice sostituendo il controllo dell’esito della richiesta  (tutta la struttura dell’if) con

response.EnsureSuccessStatusCode();

dato che il metodo EnsureSuccessStatusCode() restituisce l’HttpResponseMessage in caso di esito positivo, la nostra funzione finale può essere scritta in questo modo:

public static async Task<T> GetAsync<T> (Uri uri)
{
using (var http = new HttpClient())
{
http.DefaultRequestHeaders.Add(“Accept”, “application/json”);
var response = await http.GetAsync(uri);
string json = await response.EnsureSuccessStatusCode().Content.ReadAsStringAsync();
return JsonConvert.DeserializeObject<T>(json);
}
}

In questo modo basterà richiamare la funzione appena definita sostituendo T con il tipo di oggetto da deserializzare e uri con la url del servizio

MyStruct struct = await GetAsyncAuthenticated<MyStruct>(uri);

Nel prossimo episodio vedremo come connettersi a servizi REST autenticati.

JSON for Dummies (parte 2)

Abbiamo visto cosa è il formato JSON e come trasformare un oggetto di una classe custom in e da un oggetto JSON.

A questo punto vediamo un caso di utilizzo reale. Tipicamente vogliamo popolare la nostra app con dati che provengono da un servizio remoto. Prendiamo ad esempio questo sito http://www.geonames.org/export/JSON-webservices.html (ho semplicemente cercato con Bing “json sample web service”) che espone alcuni servizi REST restituendo i dati in formato JSON oppure XML.

Se con un browser apriamo l’indirizzo http://api.geonames.org/citiesJSON?north=44.1&south=-9.9&east=-22.4&west=55.2&lang=de&username=demo  otteniamo in download il file citiesJSON.json. L’idea è quella di scaricare questo file alla nostra app e deserializzare questo file per popolare un oggetto nella nostra app.

Per poter fare questo però abbiamo bisogno di definire una classe che corrisponda alla struttura dati contenuta nel file json. Potremmo analizzare il file citiesJSON.json ed estrapolare la struttura della classe da costruire. Le proprietà vengono serializzate come coppie nome:valore, dove il nome è sempre una stringa e il valore può essere un numero, una stringa o un null. Una coppia di parentesi graffe {} corrisponde ad un oggetto, una coppia di quadre [] corrisponde ad un array i cui elementi (oggetti delimitati da {}) sono separati da virgole.

Oppure possiamo utilizzare una funzione di Visual Studio molto comoda. Aprite il file JSON e copiatene il contenuto in memoria. Create una nuova classe e cancellate tutto il contenuto. Andate su Modifica –> Incolla Speciale –> Incolla JSON come classi.

Magicamente Visual Studio crea la classe (tutte le classi, in realtà) necessaria a decodificare il file json. Le proprietà della classe devono avere lo stesso nome con cui sono definite dentro il file JSON. Non è necessario che la classe per deserializzare abbia tutte le proprietà definite nel file JSON (i campi mancanti semplicemente non vengono deserializzati).

A questo punto possiamo scaricare il file. Utilizzerò HttpClient (lo trovate su Nuget). Ricordate che le chiamate a servizi remoti vanno fatte asincrone (utilizzando await) e quindi invocate all’interno di funzioni async.

HttpClient client = new HttpClient();

string outstring = await client.GetStringAsync(“http://api.geonames.org/citiesJSON?north=44.1&south=-9.9&east=-22.4&west=55.2&lang=de&username=demo”);

Rootobject deserializedObject = JsonConvert.DeserializeObject<Rootobject>(outstring);

Tutto qui. I dati che arrivano dal servizio remoto (qualunque cosa ci sia dentro), senza saper quasi nulla del servizio e dei dati, sono nella nostra app, pronti ad essere messi in binding.

Ma possiamo fare ancora qualcosa di meglio. Non siete costretti ad utilizzare i nomi delle proprietà o delle classi annidate così come sono nel file json (tutti minuscoli, per esempio). Nella definizione delle proprietà possiamo mettere tra parentesi quadre il nome della proprietà JSON che vogliamo deserializzare in modo da dare alla proprietà della nostra classe il valore che vogliamo.

[JsonProperty(“geonames”)]
public Geoname[] NomeCheVogliamo { get; set; }

Ricordiamoci di inserire using Newtonsoft.Json; nella nostra classe altrimenti non potremo usare JsonProperty.

TIP: Un tool per generare classi C# da JSON (ma anche VB.NET o Typescript) più potente di quello integrato in Visual Studio potete trovarlo qui https://jsonclassgenerator.codeplex.com/

JSON for Dummies (parte 1)

Abbiamo visto nella serie sul Binding come popolare l’interfaccia della vostra applicazione con dati salvati in una struttura dati. Le app moderne utilizzano dati che provengono da fonti esterne e tipicamente vengono utilizzati formati di scambio ottenuti da serializzazione dei dati. I formati più utilizzati sono l’XML e il JSON.

L’operazione di serializzazione/deserializzazione può essere gestita tramite il componente NuGet JSON.NET, utilizzando JsonConvert.DeserializeObject<T>(string json) e JsonConvert.SerializeObject(object o) o in alternativa utilizzare la classe nativa di .NET System.Runtime.Serialization.Json.DataContractJsonSerializer con i metodi ReadObject e WriteObject.

Per il nostro esempio utilizzeremo il componente di JSON.NET

Creiamo prima di tutto la nostra struttura dati:

public class MyStruct
{
public string Title { get; set; }
public string Name { get; set; }
public List<MyItem> List { get; set; }
}

    public class MyItem
{
public string Id { get; set; }
public string Name { get; set; }
public string Description { get; set; }
}

In fase di inizializzazione dell’app creiamo una istanza della mia classe e la popoliamo con valori di test

Struct = new MyStruct()
{
Title = “test”,
Name = “name”,
List = new List<MyItem>()
{
new MyItem(){Id = 0, Name=”name0″, Description= “description0″},
new MyItem(){Id = 1, Name=”name1”, Description= “description1″},
new MyItem(){Id = 2, Name=”name2”, Description= “description2”},
}
};

A questo punto otteniamo il nostro oggetto serializzato con JSON.NET semplicemente con

string serializedData = JsonConvert.SerializeObject(Struct);

Il valore della stringa serializedData, che contiene tutti i dati dell’oggetto Struct, è la seguente:

{“Title”:”test”,”Name”:”name”,”List”:[{“Id”:0,”Name”:”name0″,”Description”:”description0″},{“Id”:1,”Name”:”name1″,”Description”:”description1″},{“Id”:2,”Name”:”name2″,”Description”:”description2″}]}

Per ricreare l’oggetto dai dati serializzati bisogna semplicemente utilizzare il metodo Deserialize():

var deserializedData = JsonConvert.DeserializeObject<MyStruct>(serializedData);

che vi restituisce un oggetto di tipo MyStruct.

In questo modo avete un metodo semplice per trasformare semplicemente i vostri dati in e da una stringa di testo (che può essere salvata in locale o in remoto). Nel prossimo post vedremo come utilizzare dati JSON presi da un servizio remoto e come creare la struttura dati per la deserializzazione.