[C# Driver] ObjectId <-> string implicit conversion

2,247 views
Skip to first unread message

yngndrw

unread,
Aug 16, 2012, 4:14:35 PM8/16/12
to mongod...@googlegroups.com
Hello,

It would be nice if ObjectId could be implicitly converted to / from a string.

An example is when using a SignalR hub which has a method that takes an ObjectId parameter.

The SignalR JSON serialiser is never called (Possibly a bug with SignalR where it's not serialising structures, but that's a different matter) and SignalR ends up just trying to stuff a string value into the ObjectId parameter. This causes an error because an implisit cast cannot be performed.

Additionally a JsonConverter needs to be specified against each ObjectId property of my models for them to be serialised correctly. (Otherwise they just come out as [Object...])

Thanks,
-Andrew.

craiggwilson

unread,
Aug 16, 2012, 5:28:25 PM8/16/12
to mongod...@googlegroups.com
My advice to you is to not push ObjectId's out through any sort of api.  Rather, use strings or guids.  Your entities can be decorated with an attribute(or through the configuration api) telling it to store particular strings as ObjectIds in MongoDB, but let's you work with them as strings in your business code.

class Test
{
  [BsonRepresentation(BsonType.ObjectId)]
  public string Id { get; set; }
}

You are welcome to file a ticket at jira.mongodb.org as a feature request.  Chances are that we will not implement this as it is simply not safe, mostly for you.  The above solution is opt-in, whereas implicit conversion is not.  ObjectId's are not strings and to mix the two could be very problematic if not intended.

yngndrw

unread,
Aug 16, 2012, 5:50:37 PM8/16/12
to mongod...@googlegroups.com
Thanks for the reply.

I do see the point about the conversion being opt-in and explicit, however I disagree that using strings or GUIDs would solve the issue.

The solution you posted (Or using GUIDs for that matter) still suffers from the same issue that they are unsafe - As the field is no longer strongly typed as an ObjectId, there is nothing stopping the business logic from putting a random ID in there. This then shifts the point at which the error can occur from the UI input serialisation to the database serialisation level, meaning that there is a larger amount of code which could insert the wrong value.

Ideally any invalid data would be caught (And raised as an error) as early as possible, which in this case would be the SignalR serialisation stuff throwing an exception when an invalid string value is passed in.

Additionally, ObjectIds can be converted to / from strings without any loss and strings are required for a lot of web-based serialisation. (XML, JSON, etc) The error that you'd see is not really any different to passing a non-numeric string into the MVC model binder where it expects an integer - It would correctly fail.

For these reasons I believe that ObjectId <-> string conversion is safe within reason, but I will re-consider if I can do the conversion explicitly in a nice way. Currently I just have a string parameter which I then convert to an ObjectId using ObjectId.TryParse, but I like the idea of just being able to have a method which takes an ObjectId parameter and for it to "just work". What I have now is explicit but it isn't a very clean solution in my opinion.

Thanks,
-Andrew.

craiggwilson

unread,
Aug 16, 2012, 9:31:21 PM8/16/12
to mongod...@googlegroups.com
If SignalR, WebApi, MVC... were the only things using the driver, then it might make sense to make things a little easier for them, but that isn't true and we need to consider all users.

Regardless, I think there is probably a fairly clean way of doing this if you still want to use typed ObjectIds in your API.  Json.NET supports converters natively.  Seems like you could write one and register it up front if you know you are using Json. MVC and WebApi would let you write a ModelBinder for an ObjectId.  I haven't messed with SignalR yet, but presumably it supports this as well.

yngndrw

unread,
Aug 17, 2012, 4:20:42 PM8/17/12
to mongod...@googlegroups.com
Thinking about it, I do agree that it is just web projects which would benefit from this.

I did try using SignalR's JSON-Conversion overloading but it didn't seem to work. Looking through their code I found out why:
        public object ConvertTo(Type type)
        {
            // A non generic implementation of ToObject<T> on JToken
            using (var jsonReader = new JTokenReader(_value))
            {
                var serializer = new JsonSerializer();
                return serializer.Deserialize(jsonReader, type);
            }
        }

This is the method which parses every parameter and instead of using the serialiser I've specified it just uses a generic JsonSerializer. It seems that entire section is very much work in progress so I guess it will be solved in the future. In the mean time I will just convert them manually by using a string parameter.

Thanks for your help. :)
Reply all
Reply to author
Forward
0 new messages