2013-05-20 79 views
24

我在玩MongoDB並且有一個帶有mongodb ObjectId的對象。當我使用.NET Json()方法將其序列化時,一切都很好(但日期很糟糕!)序列化Mongo時出現JSON.NET轉換錯誤ObjectId

如果我使用JSON.NET串行器嘗試此操作,它會在嘗試序列化ObjectID時給我一個InvalidCastException

任何想法最新情況發生以及我如何解決這個問題?

using MongoDB.Driver; 
using MongoDB.Bson; 
using Newtonsoft.Json; 

//this is a route on a controller 
    public string NiceJsonPlease() 
    { 

     var q = new TestClass(); 
     q.id = new ObjectId(); 
     q.test = "just updating this"; 

     return JsonConvert.SerializeObject(q); 
    } 

    //simple test class 
    class TestClass 
    { 
     public ObjectId id; //MongoDB ObjectID 
     public string test = "hi there"; 
    } 


Exception Details: System.InvalidCastException: Specified cast is not valid. 

如果更改了控制器的方法使用附帶的.NET,它的工作原理串行OK(但是,這個人給醜陋的日期,blugh)

public JsonResult NiceJsonPlease() 
    { 

     var q = new TestClass(); 
     q.id = new ObjectId(); 
     q.test = "just updating this"; 

     return Json(q, JsonRequestBehavior.AllowGet); 
    } 
+1

啊,老的Json日期問題:http://www.hanselman.com/blog/OnTheNightmareThatIsJSONDatesPlusJSONNETAndASPNETWebAPI.aspx – Liam

+0

@Liam喜利亞姆,我居然讀了博客今天早些時候有幾分,我的理由問這個問題。 JSON.NET爲我提供了更好的日期,但是如果我在模型中包含MongoDB ObjectID並嘗試使用JSON.NET對其進行序列化,則會出錯。 – Keeno

+1

你可以顯示你的代碼嗎? – Liam

回答

20

我有一個指針從MongoDB用戶組。 https://groups.google.com/forum/?fromgroups=#!topic/mongodb-csharp/A_DXHuPscnQ

的反應是 「這似乎是個Json.NET的問題,但不是真的。還有就是自定義類型在這裏根本不知道。你需要告訴Json.NET如何序列化的ObjectId「。

所以,我採取了以下解決方案

我飾我的ObjectId與

[JsonConverter(typeof(ObjectIdConverter))] 

然後寫道,剛剛吐出的的ObjectId

class ObjectIdConverter : JsonConverter 
{ 

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) 
    { 
     serializer.Serialize(writer, value.ToString()); 

    } 

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) 
    { 
     throw new NotImplementedException(); 
    } 

    public override bool CanConvert(Type objectType) 
    { 
     return typeof(ObjectId).IsAssignableFrom(objectType); 
     //return true; 
    } 


} 
+2

這對我來說非常有用。我在這裏找到了一個完全版本的同名類:https://github.com/geersch/MySinglePageApplication/blob/master/MvcApplication/Models/ObjectIdConverter.cs –

+1

@DougJohnson你可以舉例說明如何使用這個類來將bson文檔轉換爲json,因爲我遇到了一些問題。 –

+0

@Keeno你可以舉例說明如何使用此類將bson文檔轉換爲json,因爲我遇到了一些問題 –

37

的GUID部分自定義轉換你可以使用.NET字符串類型而不是ObjectId,你只需要用BsonRepresentation來修飾它。如果您使用BsonDateTime,則會遇到相同的轉換問題。這是我的項目中使用這些裝飾器的領域類。

var jsonWriterSettings = new JsonWriterSettings { OutputMode = JsonOutputMode.Strict }; 
var json = doc.ToJson(jsonWriterSettings); 

隨着進一步:

public class DocumentMetadata 
{ 
    [BsonId] 
    [BsonRepresentation(BsonType.ObjectId)] 
    public string Id { get; set; } 
    public string Name { get; set; } 
    public string FullName { get; set; } 

    [BsonDateTimeOptions(Kind = DateTimeKind.Utc)] 
    public DateTime DownloadTime { get; set; } 
} 
+1

+1非常好!!! – IamStalker

+2

同一天:)謝謝! – Dreamcatcher

+0

優秀!!!!!! – user3311522

2

我遇到了與Web API項目類似的問題,彼時打我的頭靠在鍵盤了幾個小時之前,我發現這個線程。

最初一切工作正常,但後來我將代碼轉換爲使用我自己的自定義類,而不是mongoDB C#驅動程序文檔中推薦的BsonDocument對象後遇到問題。

http://docs.mongodb.org/ecosystem/tutorial/getting-started-with-csharp-driver/#bsondocument-object-model-vs-your-own-domain-classes

這裏VB.net等效於上面爲那些需要它的溶液;

Public Class DocumentMetadata 
    <BsonId> _ 
    <BsonRepresentation(BsonType.ObjectId)> _ 
    Public Property Id() As String 
    Public Property Name() As String 
    Public Property FullName() As String 

    <BsonDateTimeOptions(Kind := DateTimeKind.Utc)> _ 
    Public Property DownloadTime() As DateTime 
End Class 
10

1)寫的ObjectId轉換器

public class ObjectIdConverter : JsonConverter 
{ 
    public override bool CanConvert(Type objectType) 
    { 
     return objectType == typeof(ObjectId); 
    } 

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) 
    { 
     if (reader.TokenType != JsonToken.String) 
      throw new Exception($"Unexpected token parsing ObjectId. Expected String, got {reader.TokenType}."); 

     var value = (string)reader.Value; 
     return string.IsNullOrEmpty(value) ? ObjectId.Empty : new ObjectId(value); 
    } 

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) 
    { 
     if (value is ObjectId) 
     { 
      var objectId = (ObjectId)value; 
      writer.WriteValue(objectId != ObjectId.Empty ? objectId.ToString() : string.Empty); 
     } 
     else 
     { 
      throw new Exception("Expected ObjectId value."); 
     } 
    } 
} 

2)在JSON註冊。全球有全局設置NET,你不需要你的模型與大屬性

  var _serializerSettings = new JsonSerializerSettings() 
      { 
       Converters = new List<JsonConverter> { new ObjectIdConverter() } 
      }; 
+2

但最好的方法 - 使用ObjectId的字符串並在實體字段上標記[BSonRepresentation(ObjectId)] – ZOXEXIVO

0

我在VB.Net用這個代碼和工作完美的,你可以看到OBJECTID中的類,你可以做同樣的事情大關數據類型DATE。

Imports MongoDB.Bson 
    Imports MongoDB.Bson.Serialization.Attributes  
    Imports MongoDB.Driver 

Public Class _default 
    Inherits System.Web.UI.Page 

    Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load 

     Dim objMongo As New MongoClient("mongodb://192.168.111.5:27017") 
     Dim objDatabase As IMongoDatabase = objMongo.GetDatabase("local") 
     Dim objCollection = objDatabase.GetCollection(Of BsonDocument)("Test")    
     Dim _ret As New List(Of mongo_users) 

     Dim result = objCollection.Find(New BsonDocument()).ToList() 
     Dim _json_response = result.ToJson() 
     If _json_response <> "" Then 

      _ret = MongoDB.Bson.Serialization.BsonSerializer.Deserialize(Of List(Of mongo_users))(_json_response) 

     End If 

     For Each item In _ret 
      Response.Write(item.name & " " & item.last_name & "</br>") 
     Next 


    End Sub 

End Class 

Public Class mongo_users    
    <BsonId> 
    <BsonRepresentation(BsonType.ObjectId)> 
    Public Property _id() As String 
    Public Property status As Integer 
    Public Property name As String 
    Public Property last_name As String 
    Public Property colors As List(Of user_colors)  
End Class 

Public Class user_colors 
    Public Property color_name As String 
End Class