2012-04-21 105 views
2

我一直在使用RavenDB兩個小時,所以如果我錯過了一些顯而易見的道歉。序列化/反序列化系統.Uri

我使用System.Uri類型的屬性存儲非規範化視圖模型。 URI是序列化爲一個字符串,它是好,我猜,但引發此異常,當我加載文檔:

Message=Could not cast or convert from System.String to System.Uri. 
Source=Newtonsoft.Json 
StackTrace: 
    at Newtonsoft.Json.Utilities.ConvertUtils.EnsureTypeAssignable(Object value, Type initialType, Type targetType) in d:\Development\Releases\Json\Working\Src\Newtonsoft.Json\Utilities\ConvertUtils.cs:line 267 
    at Newtonsoft.Json.Utilities.ConvertUtils.ConvertOrCast(Object initialValue, CultureInfo culture, Type targetType) in d:\Development\Releases\Json\Working\Src\Newtonsoft.Json\Utilities\ConvertUtils.cs:line 244 
    at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.EnsureType(JsonReader reader, Object value, CultureInfo culture, JsonContract contract, Type targetType) in d:\Development\Releases\Json\Working\Src\Newtonsoft.Json\Serialization\JsonSerializerInternalReader.cs:line 544 
+0

Uri在數據庫中看起來像什麼? – ataddeini 2012-04-21 14:15:40

+0

「Url」:「/ about-us」 – 2012-04-21 14:16:57

回答

0

我還不能肯定是什麼Newtonsoft在幕後做,但如果它調用new System.Uri("/about-us")無在構造函數中指定UriKind.Relative將會拋出UriFormatException

因此,根據您的模型中Uri的創建方式,在存儲它之前可能需要確保它是絕對的。

我不是積極的,但我會認爲像new System.Uri("http://foo.com/about-us")這樣的Uri將被存儲爲「http://foo.com/about-us」,並且會在它返回時轉換成OK。

+0

我得到完全不同的例外。看着堆棧跟蹤和異常,似乎Newtonsoft只是試圖給我的視圖模型的System.Uri屬性分配一個字符串。 – 2012-04-21 23:39:12

5

Got it!有兩個祕密。首先是爲Uri類型創建一個JsonConverter。

public class UriJsonConverter : JsonConverter 
{ 

    public override bool CanConvert(Type objectType) 
    { 
     return object.Equals(objectType, typeof (Uri)); 
    } 

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) 
    { 
     switch (reader.TokenType) 
     { 
      case JsonToken.String: 
       return CreateUri((string) reader.Value); 
      case JsonToken.Null: 
       return null; 
      default: 
       var msg = string.Format("Unable to deserialize Uri from token type {0}", reader.TokenType); 
       throw new InvalidOperationException(msg); 
     } 
    } 

    private static Uri CreateUri(string uriString) 
    { 
     Uri uri; 
     if (!Uri.TryCreate(uriString, UriKind.Absolute, out uri)) 
      if (!Uri.TryCreate(uriString, UriKind.Absolute, out uri)) 
       if (!Uri.TryCreate(uriString, UriKind.RelativeOrAbsolute, out uri)) 
       { 
        var msg = string.Format("Unable to determine proper UriKind for Uri {0}", uriString); 
        throw new InvalidOperationException(msg); 
       } 
     return uri; 
    } 

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) 
    { 
     if (null == value) 
     { 
      writer.WriteNull(); 
      return; 
     } 

     var uri = value as Uri; 
     if (uri != null) 
     { 
      writer.WriteValue(uri.OriginalString); 
      return; 
     } 
     var msg = string.Format("Unable to serialize {0} with {1}", value.GetType(), typeof (UriJsonConverter)); 
     throw new InvalidOperationException(msg); 
    } 

} 

第二個是用RavenDB串行器註冊轉換器。

private static DocumentStore OpenStore() 
{ 
    var store = new DocumentStore() 
        { 
         ConnectionStringName = "RavenDB" 
        }; 

    store.Conventions.CustomizeJsonSerializer = CustomJsonSerializer; 

    store.Initialize(); 
    return store; 
} 

private static void CustomJsonSerializer(JsonSerializer serializer) 
{ 
    serializer.Converters.Add(new UriJsonConverter()); 
}