2012-04-21 117 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()); 
}