0

Tried to build a simple WebAPI with MongoDB, returns a Patient document based on value of _id.

Definition of Patient, Patient.cs

namespace PatientData.Models
{
    public class Patient
    {
        [BsonElement("_id")]        
        [BsonRepresentation(BsonType.ObjectId)]     
        public string  Id { get; set; }

        public string  Name { get; set; }                   
        public ICollection<Medication> Medications { get; set; }    
    }
    public class Medication 
    {
        public string Name { get; set; }
        public int Doses { get; set; }
    }
}

Database mongodb access, PatientDB.cs:

namespace PatientData.Models
{
    public static class PatientDB
    {
        static MongoClient client = new MongoClient("mongodb://localhost");
        static IMongoDatabase db = client.GetDatabase("Patients");

    public static IMongoCollection<Patient> Open()  
    {
        return db.GetCollection<Patient>("Patients");       
    }

    public static IQueryable<Patient> query()
    {
        return db.GetCollection<Patient>("Patients").AsQueryable<Patient>();       // .AsQueryable() is still availabe in driver version 2.# as an extension for collection. so .Any() is still available as well.
    }
}

}

API controller:

namespace PatientData.Controllers
{

public class PatientsController : ApiController
{
    IMongoCollection<Patient> _patients;

    public PatientsController()
    {
        _patients = PatientDB.Open();
    }
    public IEnumerable<Patient> Get()
    {
        return _patients.Find<Patient>(_=>true).ToList();   
    }

    public HttpResponseMessage Get(string id)   
    {
        var theFilter = Builders<Patient>.Filter.Eq("Id", id);
        var thePatient = _patients.FindSync<Patient>(theFilter);      

        //return (Patient)thePatient;         

        return Request.CreateResponse(thePatient);

    }

}

}

Compiled ok, got run-time exception, for example, URL

http://localhost:49270/api/Patients/5768a6f48200fa07289c93e8 Type 'MongoDB.Driver.Core.Operations.AsyncCursor`1[PatientData.Models.Patient]' cannot be serialized. Consider marking it with the DataContractAttribute attribute, and marking all of its members you want serialized with the DataMemberAttribute attribute. If the type is a collection, consider marking it with the CollectionDataContractAttribute. See the Microsoft .NET Framework documentation for other supported types.

If returned type is "Patient" not "HttpResponseMessage", and use

return (Patient)thePatient;

run-time exception is more interesting:

'System.InvalidCastException Unable to cast object of type 'MongoDB.Driver.Core.Operations.AsyncCursor`1[PatientData.Models.Patient]' to type 'PatientData.Models.Patient'.

If the cursor is typed as PatientData.Models.Patient, why can't be that type?

This is based on Scott Allen's ASP.NET MVC 5 Fundamentals, WebAPI 2, Query by ID. He's using 1.x driver

Mine is:

  • mongo server 3.2, 64-bit
  • mongo C# driver 2.2.4
SO is great
  • 3
  • 1
  • 3

2 Answers2

0

FindSync<> does not return a single object. The answer to the question below may help you as well. Difference between Find and FindAsync

Community
  • 1
  • 1
Peter4499
  • 685
  • 7
  • 15
  • this is awesome. Simplest way I did was `var thePatient = _patients.FindSync(theFilter);`. I wish Mongo's Doc can explain this in more details. – SO is great Jun 23 '16 at 22:11
0

In version 2.x driver, Find() is gone, there are FindAsync() and FindSync(), both are returning cursors which possibly hold more than one. Therefore it's like string[] is not a string, and that's what the run-time error complained about. Fortunately there is something called "extension". In my case here, simply append

.FirstOrDefault()

to make it like this

var thePatient = _patients.FindSync<Patient>(theFilter).FirstOrDefault();
SO is great
  • 3
  • 1
  • 3