Cet article est très ancien. Les choses ont bien changées depuis 2013. Le sujet abordé est conservé pour référence mais n'est certainement plus applicable en l'état.
La dernière version de Json.NET (version 4.5.11 publiée sur Nuget en novembre 2012) permet de fournir une implémentation de ITraceWriter
pour obtenir les traces générées lors des opérations de sérialisation.
Son créateur propose sur son blog un article avec un exemple d’utilisation que je reproduis ici:
Staff staff = new Staff();
staff.Name = "Arnie Admin";
staff.Roles = new List { "Administrator" };
staff.StartDate = DateTime.Now;
ITraceWriter traceWriter = new MemoryTraceWriter();
JsonConvert.SerializeObject(
staff,
new JsonSerializerSettings { TraceWriter = traceWriter, Converters = { new JavaScriptDateTimeConverter() } });
Console.WriteLine(traceWriter);
/*
2012-11-11T12:08:42.761 Info Started serializing Newtonsoft.Json.Tests.Serialization.Staff. Path ''.
2012-11-11T12:08:42.785 Info Started serializing System.DateTime with converter Newtonsoft.Json.Converters.JavaScriptDateTimeConverter. Path 'StartDate'.
2012-11-11T12:08:42.791 Info Finished serializing System.DateTime with converter Newtonsoft.Json.Converters.JavaScriptDateTimeConverter. Path 'StartDate'.
2012-11-11T12:08:42.797 Info Started serializing System.Collections.Generic.List`1[System.String]. Path 'Roles'.
2012-11-11T12:08:42.798 Info Finished serializing System.Collections.Generic.List`1[System.String]. Path 'Roles'.
2012-11-11T12:08:42.799 Info Finished serializing Newtonsoft.Json.Tests.Serialization.Staff. Path ''.
*/
Contexte WebApi
Par défaut, les contrôleurs utiliseront la classe JsonMediaTypeFormatter
pour retourner une réponse au format JSON. Et JsonMediaTypeFormatter
utilise par défaut Json.NET pour la sérialisation de la réponse.
Pour définir le ITraceWriter
à utiliser, il suffit donc de modifier la propriété SerializerSettings
du serializer au démarrage de l’application (global.asax.cs
):
protected void Application_Start()
{
// [...]
var json = GlobalConfiguration.Configuration.Formatters.JsonFormatter;
var jsonTracer = (Newtonsoft.Json.Serialization.ITraceWriter)GlobalConfiguration.Configuration.DependencyResolver.GetService(typeof(Newtonsoft.Json.Serialization.ITraceWriter));
json.SerializerSettings.TraceWriter = jsonTracer;
}
Le code ci-dessus suppose que le ITraceWriter
utilisé est résolu par le conteneur IoC.
Si la configuration par défaut n’est pas modifiée (typiquement si JsonMediaTypeFormatter
est bien utilisé et que sa propriété UseDataContractJsonSerializer
est désactivée), les opérations de sérialisation devraient générer des traces. Noter que lors de mes tests, la sérialisation d’un type primitif (comme string) ne générait aucune trace. Cela fonctionne bien avec un objet complexe comme dans le premier exemple.
Exemple d’implémentation de ITraceWriter
avec NLog
Jusqu’à présent, j’utilisais déjà un wrapper autour de NLog pour implémenter différents traceurs dont System.Web.Http.Tracing.ITraceWriter
. L’implémentation de cette nouvelle interface était donc très simple dans mon cas. Voici le code partiel:
public class NLogLogger
:
System.Web.Http.Tracing.ITraceWriter,
Newtonsoft.Json.Serialization.ITraceWriter
{
private readonly Logger _logger;
// [...]
#region Newtonsoft.Json.Serialization.ITraceWriter
public System.Diagnostics.TraceLevel LevelFilter
{
get { return System.Diagnostics.TraceLevel.Verbose; }
}
public void Trace(System.Diagnostics.TraceLevel level, string message, Exception ex)
{
const string exceptionMessageFormat = "{0}\r\n{1}";
switch (level)
{
case System.Diagnostics.TraceLevel.Off:
break;
case System.Diagnostics.TraceLevel.Info:
if (ex != null)
_logger.Info(exceptionMessageFormat, message, ex);
else
_logger.Info(message);
break;
case System.Diagnostics.TraceLevel.Warning:
if (ex != null)
_logger.Warn(exceptionMessageFormat, message, ex);
else
_logger.Warn(message);
break;
case System.Diagnostics.TraceLevel.Error:
if (ex != null)
_logger.Error(exceptionMessageFormat, message, ex);
else
_logger.Error(message);
break;
case System.Diagnostics.TraceLevel.Verbose:
default:
if (ex != null)
_logger.Debug(exceptionMessageFormat, message, ex);
else
_logger.Debug(message);
break;
}
}
#endregion
}