I'm currently applying the [BsonRepresentation(BsonType.String)]
attribute to all Guid
properties in my domain models to have those properties serialized in string format. Besides being tiresome to do, that doesn't work out sometimes, e.g. with custom Wrapper<T>
classes:
public class Wrapper<T>
{
public T Value { get; set; }
// Further properties / business logic ...
}
When T
is Guid
, the Value
property will be stored as binary data of type UuidLegacy
(as will any property of type Guid
that's not decorated with the above attribute). However, I'd like all Guid
s, including Wrapper<Guid>.Value
, to be represented as a string in the database.
Is there any way to tell the MongoDB C# driver to store all Guid
s in string format?
This can be achieved using Conventions
Something along the lines of:
var myConventions = new ConventionProfile();
myConventions.SetSerializationOptionsConvention(
new TypeRepresentationSerializationOptionsConvention(typeof (Guid), BsonType.String));
BsonClassMap.RegisterConventions(myConventions, t => t == typeof (MyClass));
This should go somewhere in your app startup.
You can read more about conventions here: http://www.mongodb.org/display/DOCS/CSharp+Driver+Serialization+Tutorial#CSharpDriverSerializationTutorial-Conventions
An alternative to performing this globally without setting a Convention
(which I believe is overkill given the actual question was effectively: "how can this be applied globally") can be done by simply calling one line of code:
BsonSerializer.RegisterSerializer(typeof(Guid),
new GuidSerializer(BsonType.String));
Just make sure this is the first thing that fires in terms of MongoDb's serialization configuration (even before class maps are registered, the same is true for the convention based solutions posted).
Personally I see this as a better solution than creating a convention with an 'always return true' predicate, that most seem to be suggesting. Conventions are great for more complex scenarios, and for grouping sets of serialization configurations, where the predicate is actually used, and multiple Conventions
are bundled into a ConventionPack
. But for simply applying a global serialization format, just keep it simple with the above line of code.
If you later decide you have a legitimate Convention
that requires a variation of this rule, just register it in order to overwrite the global rule we have set, just as your Convention
would overwrite the default global rule, which is set to have Guid's
represented as BsonType.Binary
. The net result then would be the global rule taking precedence, followed by the Convention
, which will overwrite our custom global rule only in such cases where the custom ConventionPack
is applicable (based on your custom predicate).
While using conventions will work, pay attention to two important (and related) points:
filter
parameter is required, and if the filter is too general (for example: t => true
), it can overwrite other registered conventions. Another option is to create a BSON Class Map for type Guid, which sets the representation to string:
if (!BsonClassMap.IsClassMapRegistered(typeof(Guid))) {
BsonClassMap.RegisterClassMap<Guid>(cm => {
cm.AutoMap();
cm.Conventions.SetSerializationOptionsConvention(new TypeRepresentationSerializationOptionsConvention(typeof(Guid), BsonType.String));
});
}
This should be done before any reading/writing using BsonSerializer, otherwise the default Class Map will be created, and you wont be able to change the Class Map.
ConventionProfile was deprecated. If you don't want to apply the rule globally, but only for a specific class (this should go somewhere in your app startup):
var pack = new ConventionPack { new GuidAsStringRepresentationConvention () };
ConventionRegistry.Register("GuidAsString", pack, t => t == typeof (MyClass));
public class GuidAsStringRepresentationConvention : ConventionBase, IMemberMapConvention
{
public void Apply(BsonMemberMap memberMap)
{
if (memberMap.MemberType == typeof(Guid))
{
var serializer = memberMap.GetSerializer();
var representationConfigurableSerializer = serializer as IRepresentationConfigurable;
if (representationConfigurableSerializer != null)
{
var reconfiguredSerializer = representationConfigurableSerializer.WithRepresentation(BsonType.String);
memberMap.SetSerializer(reconfiguredSerializer);
}
}
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With