2

我已经使用 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
4

2 回答 2

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());
}
于 2012-04-22T00:46:40.877 回答
0

我不肯定在Newtonsoft幕后做了什么,但如果它在没有在构造函数中new System.Uri("/about-us")指定的情况下调用,则会抛出一个。UriKind.RelativeUriFormatException

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

我不是很肯定,但我认为 Uri likenew System.Uri("http://foo.com/about-us")会被存储为“http://foo.com/about-us”,当它回来时会转换为 OK。

于 2012-04-21T15:05:59.133 回答