I componenti che in ASP.NET Web API si occupano di serializzare e deserializzare una risorsa, cioè di rappresentarla secondo uno specifico formato trasmissibile via HTTP e viceversa, sono chiamati media formatter.
I due media formatter predefiniti consentono di rappresentare le risorse gestite da una Web API in JSON e XML. Normalmente non è necessario fare alcun intervento per gestire la serializzazione in questi due formati, ma potrebbero presentarsi situazioni in cui è necessario intervenire nel processo di rappresentazione delle risorse da e verso il client. Vediamo di seguito come possiamo intervenire.
Personalizzare risultati JSON
Per quanto riguarda la rappresentazione in JSON, essa viene effettuata dal media formatter JsonMediaTypeFormatter che si basa sulla libreria Json.NET. La scelta di questa libreria da parte del team di sviluppo è dettata da ragioni di flessibilità e di prestazioni, ma se per qualche motivo si preferisse utilizzare la classe .NET DataContractJsonSerializer, questo può essere fatto con le seguenti istruzioni da inserire in corrispondenza del metodo Application_Start()
in Global.asax
:
var json = GlobalConfiguration.Configuration.Formatters.JsonFormatter;
json.UseDataContractJsonSerializer = true;
Normalmente tutte le proprietà e i campi pubblici di una risorsa vengono inclusi nella serializzazione. Per evitare che una proprietà o un campo venga incluso nel processo di serializzazione, possiamo specificare l'attributo JsonIgnore
, come nel seguente esempio:
public class Item
{
public string term { get; set; }
public string definition { get; set; }
[JsonIgnore]
public string code { get; set; }
}
Questo farà in modo che code
non sia incluso nella versione JSON della risorsa da inviare al client.
Altro aspetto controllabile della serializzazione in JSON è la generazione delle date. Il formato predefinito di Json.NET è quello previsto dallo standard ISO 8601. Per intenderci, secondo questo standard le date vengono rappresentate come stringhe analoghe a 2012-06-23T12:59:22Z
.
Se preferiamo il formato Microsoft nella forma \/Date(1234)\/
occorre applicare le seguenti impostazioni:
var json = GlobalConfiguration.Configuration.Formatters.JsonFormatter;
json.SerializerSettings.DateFormatHandling
= Newtonsoft.Json.DateFormatHandling.MicrosoftDateFormat;
Personalizzare riusultati XML
Anche per la serializzazione in XML è possibile effettuare delle personalizzazioni. Ad esempio, se al posto della classe predefinita DataContractSerializer volessimo utilizzare XmlSerializer, dovremmo scrivere le seguenti istruzioni:
var xml = GlobalConfiguration.Configuration.Formatters.XmlFormatter;
xml.UseXmlSerializer = true;
Per la serializzazione XML è prevista anche la possibilità di scegliere un serializzatore diverso in base al tipo di risorsa da rappresentare. Nel seguente esempio utilizziamo XmlSerializer
soltanto per la classe Item
, mantenendo il serializzatore predefinito per le eventuali altre risorse gestite dalla nostra API:
var xml = GlobalConfiguration.Configuration.Formatters.XmlFormatter;
xml.SetSerializer(new XmlSerializer(typeof(Item)));
Per avere un maggior controllo su entrambi i tipi di serializzazione è possibile scegliere un approccio esplicito basato sull'utilizzo degli attributi DataContract e DataMember. Infatti, mentre normalmente la serializzazione delle risorse avviene in maniera implicita, cioè una risorsa viene serializzata seguendo le regole previste dallo specifico media formatter, con un approccio esplicito siamo noi a dire cosa può essere serializzato e come.
Prendiamo in considerazione il seguente codice:
[DataContract]
public class Item
{
[DataMember]
private int id;
[DataMember]
public string term { get; set; }
[DataMember]
public string definition { get; set; }
[DataMember(Name="topic")]
public string category { get; set; }
public string code { get; set; }
}
L'attributo DataContract indica che la classe è da serializzare seguendo le indicazioni fornite dallo sviluppatore. Se non viene specificato questo attributo, ogni associazione dell'attributo DataMember ai membri della classe verrà ignorata. Soltanto i membri marcati dall'attributo DataMember verranno presi in considerazione dal serializzatore, indipendentemente dalla loro accessibilità.
Nel nostro caso, pertanto, verranno inclusi il campo id
e le proprietà term
, definition
, e category
. Per quest'ultima proprietà, in particolare, verrà generato il nome topic anziché category
.
In sintesi, un esempio di serializzazione in JSON di questa classe potrebbe essere la seguente:
{ "id":"123"
"term":"API",
"definition":"Insieme di subroutine o di funzioni che ...",
"topic":"Programming"
}