开发者

MongoDB C#: ID Serialization best pattern

开发者 https://www.devze.com 2023-04-11 20:04 出处:网络
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

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);
  });
0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号