【问题标题】:Deserialization Error ASP.NET MongoDB反序列化错误 ASP.NET MongoDB
【发布时间】:2013-01-11 11:04:12
【问题描述】:

我正在尝试通过 ASP.NET MVC 4 中内置的 REST api 检索 MongoDB 集合中的所有文档,当我输入 localhost:50491/api/document: 时遇到错误:

反序列化 Acord_Rest_API.Models.Document 类的 Id 属性时出错:无法从 BsonType ObjectId 反序列化字符串。

我的控制器看起来像:

public class DocumentController : ApiController
{
    public readonly MongoConnectionHelper<Document> docs;

    public DocumentController()
    {
        docs = new MongoConnectionHelper<Document>();
    }

    public IList<Document> getAllDocs()
    {
        var alldocs = docs.collection.FindAll();
        return alldocs.ToList();
    }
}

我的 MongoDB 文档是这样的?

我在这里错过了什么?

我的类连接到数据库:

public class MongoConnectionHelper<T> where T: class
{
    public MongoCollection<T> collection { get; private set; }

    public MongoConnectionHelper()
    {
        string connectionString = "mongodb://127.0.0.1";
        var server = MongoServer.Create(connectionString);
        if (server.State == MongoServerState.Disconnected)
        {
            server.Connect();
        }
        var conn = server.GetDatabase("Acord");
        collection = conn.GetCollection<T>("Mappings");
    }
}

编辑这里是我的解决方案:

MongoConnectionHelper 连接到数据库,DocumentController 具有检索所有文档的方法,并且 Document 包含您在答案中建议的内容。

这里编辑的是 Document 类:

[DataContract]
public class Document
{
    public ObjectId _id { get; set; }

    [DataMember]
    public string MongoId
    {
        get { return _id.ToString(); }
        set { _id = ObjectId.Parse(value); }
    }
    public IList<string> alldocs { get; set; }
}

【问题讨论】:

    标签: c# mongodb rest mongodb-.net-driver 10gen-csharp-driver


    【解决方案1】:

    Mongo Id 不是“字符串”,Mongo.Bson 库不会自动将其序列化为字符串。如果您使用的是 Mongo.Bson 库,则需要将类的 id 属性设置为该库中可用的 ObjectId 类型。

    这里的问题是 .net 序列化程序不知道如何序列化自定义类型 ObjectId,它是 mongo 内置的 Id(不知道为什么)。它没有标记为 [Serializable],因此您必须让 ASP.NET 绕过它或创建另一个没有的类并将其转换为字符串。

    如果您需要在您的应用程序中使用字符串,您应该禁用 MongoId 到 xml 的序列化(如果您正在尝试这样做),然后您可以将这样的属性添加到您的类中:

    [XmlIgnore]
    public ObjectId _id { get; set; }
    
    public string MongoId
    {
        get { return _id.ToString(); }
        set { _id = ObjectId.Parse(value); }
    }
    

    另一种方法是创建一个单独的映射类来管理返回数据。

    编辑在这种情况下,您应该使用“选择加入”方法。这包括将您的班级装饰成如下所示:

    [DataContract]
    public class Document
    {
        public ObjectId _id { get; set; }
    
        [DataMember]
        public string MongoId
        {
            get { return _id.ToString(); }
            set { _id = ObjectId.Parse(value); }
        }
    

    ...

    DataMember 将仅标记这些属性以进行序列化。您是否为“文档”对象使用 POCO 类?如果是这样,上面应该可以正常工作。

    不过,我建议创建“文档”对象的映射视图以公开传递。在这些情况下,您几乎总是想要一个与实际数据库实体略有不同的“合同”

    【讨论】:

    • 我已经编辑了问题并添加了我的连接。我想将 FindAll 的结果返回给 Json。
    • 您如何建议我创建文档的映射视图?带接口?或者这是一个愚蠢的问题?
    • 一点也不,有很多方法可以做到这一点,如果没有在 VS 中看到解决方案的结构,很难给出建议。包含您映射到的类的合同文件夹始终是一个不错的文件夹。合同是它自己的类,您可以使用 linq ...Select(x => new DocumentContract() { MongoId = ObjectId.ToString(), A = xA, B = xB ... 等或 Automapper 之类的工具对其进行映射如果你有很多不同的课程。
    • 谢谢,我已经编辑了问题并添加了解决方案的截图
    • 问题不在于看起来的宁静部分,而在于数据访问部分。
    【解决方案2】:

    更简单的方法是告诉 MongoDB 将字符串字段视为 ObjectId。 您可以使用BsonType 属性轻松完成。

    [BsonRepresentation(BsonType.ObjectId)]
    public string _id { get; set; }
    

    【讨论】:

    • 你为我节省了很多时间。谢谢
    【解决方案3】:

    我认为您缺少 [BsonId] 约定 所以你的班级应该是这样的:

    [DataContract]
    public class Document
    {
        [BsonId]
        public ObjectId _id { get; set; }
    
        [DataMember]
        public string MongoId
        {
            get { return _id.ToString(); }
            set { _id = ObjectId.Parse(value); }
        }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-06-25
      • 2014-02-19
      • 2012-01-01
      • 1970-01-01
      • 2011-09-02
      • 1970-01-01
      • 1970-01-01
      • 2013-01-07
      相关资源
      最近更新 更多