skip to Main Content

My mongodb user collection is of following schema:

{
    _id: ObjectId("6420eb68cd0df40a33b0ead7"),
    FirstName: 'Ashutosh',
    LastName: 'Garg',
    Email: '[email protected]',
    Password: 'password',
    Role: 'Tenant',
    Properties: [
        ObjectId("6420eeb8cd0df40a33b0eadb")
    ]
}

My User.cs is:

using MongoDB.Bson;
using MongoDB.Bson.Serialization.Attributes;
using MongoDB.Driver;
using System.Text.Json.Serialization;

namespace webapi.Models
{
    public class User
    {
        [BsonId]
        [BsonRepresentation(BsonType.ObjectId)]
        public String? Id { get; set; }
        public string? FirstName { get; set; }
        public string? LastName { get; set; }
        public string Email { get; set; }
        public string Password { get; set; }
        public string Role { get; set; }
        public List<ObjectId>? Properties { get; set; }
    }
}

This is my Login Service:

using Microsoft.Extensions.Options;
using MongoDB.Driver;
using webapi.Models;

namespace webapi.Services
{
    public class LoginService
    {
        private readonly IMongoCollection<User> _userCollection;
        public LoginService(IOptions<PropertyManagementDatabaseSettings> propertyManagementDatabaseSettings)
        {
            var mongoClient = new MongoClient(propertyManagementDatabaseSettings.Value.ConnectionString);
            var mongoDatabase = mongoClient.GetDatabase(propertyManagementDatabaseSettings.Value.DatabaseName);
            _userCollection = mongoDatabase.GetCollection<User>(propertyManagementDatabaseSettings.Value.UserCollectionName);
        }
        public async Task<User?> LoginAsync(string Email, string Password) =>
            await _userCollection.Find(x => x.Email == Email && x.Password == Password).FirstOrDefaultAsync();
        public async Task RegisterAsync(User newUser) =>
            await _userCollection.InsertOneAsync(newUser);
    }
}

This is my Login Controller:

using Microsoft.AspNetCore.Cors;
using Microsoft.AspNetCore.Mvc;
using webapi.Services;
using webapi.Models;

namespace webapi.Controllers
{
    [ApiController]
    [Route("[controller]")]
    public class LoginController : ControllerBase
    {
        private readonly LoginService _loginService;
        public LoginController(LoginService loginService)
        {
            _loginService = loginService;
        }
        [EnableCors("Policy1")]
        [HttpGet("{Email}/{Password}")]
        public async Task<ActionResult<User>> Get(string Email, string Password)
        {
            var user = await _loginService.LoginAsync(Email, Password);
            if (user == null) { return NotFound(); }
            return user;
        }
        [EnableCors("Policy1")]
        [HttpPost]
        public async Task<IActionResult> Post(User newUser)
        {
            await _loginService.RegisterAsync(newUser);
            return CreatedAtAction(nameof(Get), new { id = newUser.Id }, newUser);
        }
    }
}

When I try to login using Swagger with email as [email protected] and password as password, I get the following response body:

{
   "Id":"6420eb68cd0df40a33b0ead7",
   "FirstName":"Ashutosh",
   "LastName":"Garg",
   "Email":"[email protected]",
   "Password":"password",
   "Role":"Tenant",
   "Properties":[
      {
         "Timestamp":1679879864,
         "Machine":13438452,
         "Pid":2611,
         "Increment":11594459,
         "CreationTime":"2023-03-27T01:17:44Z"
      }
   ]
}

But I want to get it in the following format

{
    Id: ObjectId("6420eb68cd0df40a33b0ead7"),
    FirstName: 'Ashutosh',
    LastName: 'Garg',
    Email: '[email protected]',
    Password: 'password',
    Role: 'Tenant',
    Properties: [
        ObjectId("6420eeb8cd0df40a33b0eadb")
    ]
}

What am I doing wrong? What should I try?

I have tried renaming the Properties field, I have also tried changing the datatype to string[] but it gives rise to –

System.FormatException: An error occurred while deserializing the RelatedProperties property of class webapi.Models.User: Cannot deserialize a ‘String’ from BsonType ‘ObjectId’.
—> System.FormatException: Cannot deserialize a ‘String’ from BsonType ‘ObjectId’.

2

Answers


  1. The mongo driver know how to serialize/deserialize the ObjectId type but your json serializer doesn’t.

    You need to write a custom converter for newtonsoft (or for System.Text.Serialization, depending what you use) and specify how to convert the mongo ObjectId type to string.

    Here is the documentation from microsoft : https://learn.microsoft.com/en-us/dotnet/standard/serialization/system-text-json/converters-how-to?pivots=dotnet-7-0

    Login or Signup to reply.
  2. To use mongodb ObjectId you have to handle the HTTP stream yourself.
    This is quite simple

    [HttpPost]
    public async Task<IActionResult> Test()
    {
        using (StreamReader sr = new StreamReader(Request.Body))
        {
            User newUser = MongoDB.Bson.Serialization.BsonSerializer.Deserialize<User>(await sr.ReadToEndAsync());
            await _loginService.RegisterAsync(newUser);
            return CreatedAtAction(nameof(Get), new { id = newUser.Id }, newUser);
        }
    }
    

    More examples

    https://github.com/iso8859/learn-mongodb-by-example/blob/main/dotnet/01%20-%20Begin/03%20-%20Serialization.cs

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search