EF 4 Entity mit Json.Net Serialisieren
Kleiner Trick zum Serialisieren von Entity-Framework Objekten mit Newtonsoft Json.NetDas Entity-Framework generiert für die Entity-Klassen Proxies, die den Zugriff auf virtuelle Properties und Collections kapseln. Diese Proxy-Klassen werden per Reflection.Emit zur Laufzeit erzeugt. Hiermit kann Newtonsoft Json.Net leider nichts anfangen.
Diese ausgezeichnete Bibliothek zur Serialisierung von .Net Objekten nach Json und vice-versa bietet aber vielseitige Erweiterungsmöglichkeiten, so dass auch das oben genannte Problem umschifft werden kann.
Um also zu verhindern, dass Json.Net versucht eine Property eine Proxy-Klasse zu serialisieren (was zu einer Exception führt), dürfen nur Member-Variablen mit bekannten Typen beachtet werden. Hierzu kann in den JsonSerializerSettings ein IContractResolver angegeben werden:
var settings = new JsonSerializerSettings()
{
ReferenceLoopHandling = ReferenceLoopHandling.Ignore,
TypeNameHandling = TypeNameHandling.Objects,
ContractResolver = new EFContractResolver()
};
var json = JsonConvert.SerializeObject(query, Formatting.Indented, settings);
Der EFContractResolver verhält sich im grossen und ganzen wie der Json.Net DefaultContractResolver. Dieser enthält eine überschreibbare Methode GetSerializableMembers in der diejenigen Member eines Typs eingeschlossen werden, die in der Json-Ausgabe wieder aufsuchen sollen. Da wir die zusätzlichen Member des Proxies ignorieren wollen, nutzen wir die Fähigkeit der EF-ObjectContext auf alle Entity-Proxy-Abbildungen innerhalb einer App-Domain zuzugreifen:
public class EFContractResolver : DefaultContractResolver
{
protected override List GetSerializableMembers(Type proxyType)
{
var knownProxyTypes = ObjectContext.GetKnownProxyTypes();
if (!knownProxyTypes.Contains(proxyType))
return base.GetSerializableMembers(proxyType);
var entityType = ObjectContext.GetObjectType(proxyType);
return base.GetSerializableMembers(entityType);
}
}
An dieser Stelle sind natürlich noch andere Filter-Möglichkeiten denkbar, z.B. Sichtbarkeit per Display-Attribut oder die Zugriffssteuerung per Authorize-Attribut.