I need to store a NodaTime LocalDateTime in an Akavache cache.
I've created a simple app which takes the following class and stores/retrieves it in/from an Akavache cache:
public class TestModel
{
public string Name { get; set; }
public LocalDateTime StartDateTimeLocal {get; set;}
public DateTime StartDateTimeUtc {get;set;}
}
When this is stored in and retrieved from the cache, the StartDateTimeLocal property hasn't been populated.
It seems that Akavache isn't aware of how to serialise/deserialize a LocalDateTime.
Is it possible to register types with Akavache or supply a custom serialisation for unknown types?
Console application to demonstrate it:
using Akavache;
using NodaTime;
using System;
using System.Reactive.Linq;
namespace AkavacheNodaTimeCore
{
class Program
{
static TestModel BeforeModel;
static TestModel AfterModel;
static void Main(string[] args)
{
// Note that we're using Akavache 6.0.27, to match the version we're using in our live system.
BlobCache.ApplicationName = "AkavacheNodaTimeCore";
BlobCache.EnsureInitialized();
BeforeModel = new TestModel()
{
StartLocalDateTime = LocalDateTime.FromDateTime(DateTime.Now),
StartDateTime = DateTime.UtcNow,
};
Console.WriteLine($"Before:LocalDateTime='{BeforeModel.StartLocalDateTime}' DateTime='{BeforeModel.StartDateTime}'");
CycleTheModels();
Console.WriteLine($"After: LocalDateTime='{AfterModel.StartLocalDateTime}' DateTime='{AfterModel.StartDateTime}'");
Console.WriteLine("Note that Akavache retrieves DateTimes as DateTimeKind.Local, so DateTime before and after above will differ.");
Console.WriteLine("Press any key to continue.");
var y = Console.ReadKey();
}
/// <summary>
/// Puts a model into Akavache and retrieves a new one so we can compare.
/// </summary>
static async void CycleTheModels()
{
await BlobCache.InMemory.Invalidate("model");
await BlobCache.InMemory.InsertObject("model", BeforeModel);
AfterModel = await BlobCache.InMemory.GetObject<TestModel>("model");
}
}
}
TestModel class:
using NodaTime;
using System;
namespace AkavacheNodaTimeCore
{
public class TestModel
{
public string Name { get; set; }
public LocalDateTime StartLocalDateTime { get; set; }
public DateTime StartDateTime {get;set;}
}
}
I have added a Git repo with the above in a console application which demonstrates the problem.
You need to configure the JsonSerializerSettings
that Akavache uses with Json.NET. You'll need a reference to NodaTime.Serialization.JsonNet
, at which point you can create a serializer settings instance, configure it for Noda Time, then add that as a dependency in Splat (which Akavache uses). I haven't used Splat before, so it's possible that this isn't the right way of doing it, but it works with your example:
using Newtonsoft.Json;
using NodaTime.Serialization.JsonNet;
using Splat;
...
// This should be before any of your other code.
var settings = new JsonSerializerSettings();
settings.ConfigureForNodaTime(DateTimeZoneProviders.Tzdb);
Locator.CurrentMutable.RegisterConstant(settings, typeof(JsonSerializerSettings));
It may be worth filing in issue in the Akavache repo to request more documentation for customization of serialization settings - the above works, but was guesswork and a little bit of source code investigation.