序列化/反序列化System.Uri

时间:2012-04-21 14:08:51

标签: serialization ravendb

我一直在使用RavenDB两个小时,所以如果我错过了一些明显的东西,请道歉。

我正在使用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

2 个答案:

答案 0 :(得分:5)

知道了!有两个秘密。第一种是为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());
}

答案 1 :(得分:0)

我不肯定Newtonsoft在幕后做了什么,但如果它在构造函数中没有指定new System.Uri("/about-us")而调用UriKind.Relative,则会抛出UriFormatException。< / p>

因此,根据您在模型中创建Uri的方式,您可以选择在存储之前确保它是绝对的。

我不是肯定的,但我认为像new System.Uri("http://foo.com/about-us")这样的Uri会被存储为“http://foo.com/about-us”,并且会在它恢复时转换为OK。