MongoDB C#: ID Serialization best pattern
I have a class User
and I need to work with them in web services.
Then problem is that if I try to serialize Id
that is type of BsonObjectId
, I see
that have an empty property, that have an empty property, and so on ...
I have write this workaround in order, it's is a good solution?
public partial class i_User
{
[BsonId(IdGenerator = typeof(BsonObjectIdGenerator))]
[NonSerialized]
public BsonObjectId _id;
public String Id
{
get
{
return this._id.ToString();
}
}
}
In this way, I can keep _Id
as BsonObjectId
but I send an string representation over the web in the property Id
.
Another solution is to work with StringObjectIdGenerator
public partial class i_User
{
[BsonId(IdGenerator = typeof(StringObjectIdGenerator))]
public String id;
}
But is see that MongoDB will开发者_开发问答 store a string
into database instead of ObjectId
.
What is the best approach in order to work in a serialization environmental like web services and/or an client-server (Flash+C#)?
If I understand you correctly, you want to access the Id
property as a string, but have the Id
saved as an ObjectId
in MongoDB. This can be accomplished using BsonRepresentation
with BsonId
.
[BsonId]
[BsonRepresentation(BsonType.ObjectId)]
public string Id { get; set; }
Details can be found here.
If you want to do it with a Class Map - this is the way to do it:
BsonClassMap.RegisterClassMap<i_User>(cm =>
{
cm.AutoMap();
cm.SetIdMember(cm.GetMemberMap(x => x.Id)
.SetIdGenerator(StringObjectIdGenerator.Instance));
});
There is also a more generic approach using conventions. This approach allows your to setup rules for all models in one place.
First. Add a convention for ID generator
public class IdGeneratorConvention : ConventionBase, IPostProcessingConvention
{
public void PostProcess(BsonClassMap classMap)
{
var idMemberMap = classMap.IdMemberMap;
if (idMemberMap == null || idMemberMap.IdGenerator != null)
{
return;
}
idMemberMap.SetIdGenerator(StringObjectIdGenerator.Instance);
}
}
Second. Register our convention. Register
method must be called before the first query.
var conventionPack = new ConventionPack { new IdGeneratorConvention() };
ConventionRegistry.Register("Pack", conventionPack, x => true);
Working with the ASP minimal APIs and with record
types for models, here is what works for me.
Basic custom converter:
using MongoDB.Bson;
using System.Text.Json;
using System.Text.Json.Serialization;
public class ObjectIdJsonConverter : JsonConverter<ObjectId> {
public override ObjectId Read(ref Utf8JsonReader reader, Type typeToConvert,
JsonSerializerOptions options) => new ObjectId(reader.GetString());
public override void Write(Utf8JsonWriter writer, ObjectId value,
JsonSerializerOptions options) => writer.WriteStringValue(value.ToString());
}
The record:
using System.Text.Json.Serialization;
using MongoDB.Bson;
public record User(
[property: JsonConverter(typeof(ObjectIdJsonConverter))]
ObjectId Id)
In the controller:
app.MapGet("/user/{id}",
async (string id, UserService userService) => {
var user = await userService.Find(id);
return Results.Json(user);
});
精彩评论