NodaTime with MongoDB: Value class NodaTime.ZonedDateTime cannot be deserialized
c#, mongodb, mongodb-.net-driver, nodatime
Solution
Nevermind, finally after much reading and experimenting, found it finally out. I wrote a custom `BsonBaseSerializer` implementation to handle `ZonedDateTime`.
Here is the code of my `ZonedDateTimeSerializer`:
/// <summary>
/// Serializer for the Noda
/// </summary>
public class ZonedDateTimeSerializer : BsonBaseSerializer
{
private static ZonedDateTimeSerializer __instance = new ZonedDateTimeSerializer();
/// <summary>
/// Initializes a new instance of the ZonedDateTimeSerializer class.
/// </summary>
public ZonedDateTimeSerializer()
{
}
/// <summary>
/// Gets an instance of the ZonedDateTimeSerializer class.
/// </summary>
public static ZonedDateTimeSerializer Instance
{
get { return __instance; }
}
/// <summary>
/// Deserializes an object from a BsonReader.
/// </summary>
/// <param name="bsonReader">The BsonReader.</param>
/// <param name="nominalType">The nominal type of the object.</param>
/// <param name="actualType">The actual type of the object.</param>
/// <param name="options">The serialization options.</param>
/// <returns>
/// An object.
/// </returns>
public override object Deserialize(BsonReader bsonReader, Type nominalType, Type actualType, IBsonSerializationOptions options)
{
VerifyTypes(nominalType, actualType, typeof(ZonedDateTime));
var bsonType = bsonReader.GetCurrentBsonType();
if (bsonType == BsonType.DateTime)
{
var millisecondsSinceEpoch = bsonReader.ReadDateTime();
return new Instant(millisecondsSinceEpoch).InUtc();
}
throw new InvalidOperationException(string.Format("Cannot deserialize ZonedDateTime from BsonType {0}.", bsonType));
}
/// <summary>
/// Serializes an object to a BsonWriter.
/// </summary>
/// <param name="bsonWriter">The BsonWriter.</param>
/// <param name="nominalType">The nominal type.</param>
/// <param name="value">The object.</param>
/// <param name="options">The serialization options.</param>
public override void Serialize(BsonWriter bsonWriter, Type nominalType, object value, IBsonSerializationOptions options)
{
if (value == null)
throw new ArgumentNullException("value");
var ZonedDateTime = (ZonedDateTime)value;
bsonWriter.WriteDateTime(ZonedDateTime.ToInstant().Ticks);
}
}
Don't forget to register the Serializer. I wasn't able to find out how to register the Serializer per type, but you can register it per type, which looks like this:
BsonClassMap.RegisterClassMap<MyPOCO>(cm =>
{
cm.AutoMap();
cm.GetMemberMap(a => a.SomeDateTime).SetSerializer(ZonedDateTimeSerializer.Instance);
});
Hope this helps.
Problem
I'm using latest versions of NodaTime and Mongo DB Official Driver. I have a simple POCO class which uses NodaTime's `ZonedDateTime` as a replacement for the .NET DateTime in a few Properties. ``` public class MyPOCO { [BsonId] [Key] public ObjectId SomeId { get; set; } public string SomeProperty { get; set; } public ZonedDateTime SomeDateTime { get; set; } } ``` I can put the Model into the collection easily, but when I try to read queried Models, I get the following `MongoDB.Bson.BsonSerializationException`: Value class NodaTime.ZonedDateTime cannot be deserialized What`s a good or the best practice to solve/work around this issue? UPDATE After posting my solution to the problem, I'm facing a possible new issue... When I query the collection and use the DateTime in my query, like `where SomeDateTime < now' (where`now`is a variable I create from system time) it seems that each document must be deserialized using my`ZonedDateTimeSerializer` before the where clause can be evaluated. This looks like a big performance issue, doesn't it? I really have to think about going back to the BCL DateTime again, even if it hurts. UPDATE 2 I'm accepting my solution using `ZonedDateTimeSerializer`, but I'm not feeling comfortable with NodaTime in combination with MongoDB, while both are great individual solutions. But they just don't work well together at the moment without heavy manipulation.