I've reproduced this using the latest version of Json.NET from nuget and the just released v1.8.3 of the C# driver.
It turns out that Json NET is calling the explicit implementation of IConvertible.ToType in class ObjectId with a conversionType equal to System.Object, which we were not expecting and which results in the C# driver throwing an InvalidCastException. I've created a CSHARP ticket for this issue:
However, after changing the C# driver's implementation of ToType to support type object, I now get a stack overflow in Json.NET when attempting to serialize the TestClass.
I've isolated the issue below so that it can be reproduced using only Json NET. The call to JsonConvert.SerializeObject results in a StackOverflowException being thrown. Perhaps you could take a look at this from the Json.NET side and help me figure out if I'm doing something wrong.
using System;
using Newtonsoft.Json;
namespace TestJsonNetWithObjectId
{
public class ConvertibleId : IConvertible
{
public int Value;
TypeCode IConvertible.GetTypeCode() { return TypeCode.Object; }
object IConvertible.ToType(Type conversionType, IFormatProvider provider)
{
if (conversionType == typeof(object)) { return this; }
if (conversionType == typeof(int)) { return (int)Value; }
if (conversionType == typeof(long)) { return (long)Value; }
throw new InvalidCastException();
}
bool IConvertible.ToBoolean(IFormatProvider provider) { throw new InvalidCastException(); }
byte IConvertible.ToByte(IFormatProvider provider) { throw new InvalidCastException(); }
char IConvertible.ToChar(IFormatProvider provider) { throw new InvalidCastException(); }
DateTime IConvertible.ToDateTime(IFormatProvider provider) { throw new InvalidCastException(); }
decimal IConvertible.ToDecimal(IFormatProvider provider) { throw new InvalidCastException(); }
double IConvertible.ToDouble(IFormatProvider provider) { throw new InvalidCastException(); }
short IConvertible.ToInt16(IFormatProvider provider) { return (short)Value; }
int IConvertible.ToInt32(IFormatProvider provider) { return Value; }
long IConvertible.ToInt64(IFormatProvider provider) { return (long)Value; }
sbyte IConvertible.ToSByte(IFormatProvider provider) { throw new InvalidCastException(); }
float IConvertible.ToSingle(IFormatProvider provider) { throw new InvalidCastException(); }
string IConvertible.ToString(IFormatProvider provider) { throw new InvalidCastException(); }
ushort IConvertible.ToUInt16(IFormatProvider provider) { throw new InvalidCastException(); }
uint IConvertible.ToUInt32(IFormatProvider provider) { throw new InvalidCastException(); }
ulong IConvertible.ToUInt64(IFormatProvider provider) { throw new InvalidCastException(); }
}
public class TestClass
{
public ConvertibleId Id;
public int X;
}
public static class Program
{
public static void Main(string[] args)
{
var c = new TestClass { Id = new ConvertibleId { Value = 1 }, X = 2 };
var s = JsonConvert.SerializeObject(c); // throws a StackOverflowException
}
}
}