Detta är del av en artikelserie Guppy – Hur bygger man en riktig tjänst med Azure Mobile Services?

Azure Mobile Services stödjer de vanligasta datatyperna såsom string, bool, DateTime och numeriska datatyper, vilka är de som man oftast använder. Men om man exempelvis vill spara en TimeSpan eller någon annan spännande datatyp måste man hjälpa till med konverteringen mellan typen och JSon, vilket är själva transportprotokollet mellan klienten och tjänsten.

Detta inlägg tar mycket inspiration ifrån Supporting arbitrary types in Azure Mobile Services managed client.

Säg att vi har en klass som vi vill spara i Azure Mobile Services som ser ut så här:

[DataTable(Name ="session")]
public class Session
{
[DataMember(Name="id")]
public int Id;
[DataMember(Name="name")]
public string Name;
[DataMember(Name = "length")]
public TimeSpan Length;
}

Om vi sedan gör ett anrop för att spara en nytt objekt i tjänsten:

var aSession = new Session()
{
Name = "Go with C#",
Length = new TimeSpan(1,10,0)
};
await App.MobileService.GetTable<Session>().InsertAsync(aSession);

Så får vi följande fel ifrån tjänsten:

Cannot serialize member 'length' of type 'System.TimeSpan' declared on type 'Session'.

Lösning

För att lösa detta behöver vi implementera ett interface, vilket använts sedan av klienten för att konvertera mellan olika datatyper när datat skickas och tas emot.

Interfacet heter IDataMemberJsonConverter, vilket har två metoder ConvertFromJson och ConvertToJson.

OBSERVERA – Det är olika metodsignaturer för ConvertFromJson beroende på om klienten är Windows 8 eller Windows Phone 8.

En implementation för detta interface för TimeSpan och Windows 8 och Windows Phone 8

Windows 8

class TimeSpanJsonConverter : IDataMemberJsonConverter
{
private static readonly IJsonValue NullJson = JsonValue.Parse("null");
public object ConvertFromJson(Windows.Data.Json.IJsonValue value)
{
TimeSpan result = default(TimeSpan);
if (value != null && value.ValueType == JsonValueType.String)
{
result = TimeSpan.Parse(value.GetString());
}
return result;
}
public Windows.Data.Json.IJsonValue ConvertToJson(object instance)
{
if (instance is TimeSpan)
{
TimeSpan timeSpan = (TimeSpan)instance;
return JsonValue.CreateStringValue(timeSpan.ToString());
}
else
{
return NullJson;
}
}
}

Windows Phone 8

class TimeSpanJsonConverter : IDataMemberJsonConverter
{
public object ConvertFromJson(JToken value)
{
TimeSpan result = default(TimeSpan);
if (value != null)
{
}
return result;
}
public JToken ConvertToJson(object instance)
{
if (instance is TimeSpan)
{
TimeSpan timeSpan = (TimeSpan) instance;
return JValue.CreateString(timeSpan.ToString());
}
else
{
return default(JValue);
}
}
}

Vi behöver lägga till attribut i klassen Session, DataMemberJsonConverter, som talar om att fältet Length skall konvertas när det skickas och tas emot.

public class Session
{
[DataMember(Name="id")]
public int Id;
[DataMember(Name="name")]
public string Name;
[DataMember(Name = "length"), DataMemberJsonConverter(ConverterType = typeof(TimeSpanJsonConverter))]
public TimeSpan Length;
}

Sedan funkar allt som vanligt, inklusive automatgenerering av fältet i tabellen, om det ej finns tidigare.