【问题标题】:JSON.Net JsonConverter for DbGeography用于 DbGeography 的 JSON.Net JsonConverter
【发布时间】:2014-07-14 18:33:35
【问题描述】:

为此奋斗了很久......

基本上我有一个具有DbGeography 属性的模型优先EF5 对象。我想申请一个JsonConverter,让它作为简单的纬度/经度值往返。我正在使用 WebAPI。

像这样寻找 JSON 输出和输入:

{
    "location":
    {
        "geopoint":
        {
            "latitude":40.770712,
            "longitude":-73.962011
        }
    }
}

这是我的类定义和 JsonConverter:

[MetadataType(typeof(QueryLocationMetadata))]
partial class Location
{
}

public class QueryLocationMetadata
{
    [JsonConverter(typeof(DbGeographyConverter))]
    public virtual DbGeography GeoPoint { get; set; }
}


public class DbGeographyConverter : JsonConverter
{
    private const string LATITUDE_KEY = "latitude";
    private const string LONGITUDE_KEY = "longitude";

    public override bool CanConvert(Type objectType)
    {
        return objectType.Equals(typeof(DbGeography));
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        if (reader.TokenType == JsonToken.Null)
            return default(DbGeography);

        var jObject = JObject.Load(reader);

        if (!jObject.HasValues || (jObject.Property(LATITUDE_KEY) == null || jObject.Property(LONGITUDE_KEY) == null))
            return default(DbGeography);

        string wkt = string.Format("POINT({1} {0})", jObject[LATITUDE_KEY], jObject[LONGITUDE_KEY]);
        return DbGeography.FromText(wkt, DbGeography.DefaultCoordinateSystemId);
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        var dbGeography = value as DbGeography;

        serializer.Serialize(writer, dbGeography == null || dbGeography.IsEmpty ? null : new { latitude = dbGeography.Latitude.Value, longitude = dbGeography.Longitude.Value });
    }
}

因此,使用它我能够成功地序列化甚至正确反序列化对象,但在我点击ApiController 操作之前,我收到以下错误:

System.Data.SqlTypes.SqlNullValueException: Data is Null. This method or property cannot be called on Null values.
   at System.Data.SqlTypes.SqlDouble.get_Value()
   at GetValueFromSqlDouble(Object )
   at System.Web.Http.Metadata.Providers.AssociatedMetadataProvider`1.<>c__DisplayClass3.<GetMetadataForPropertiesImpl>b__0()
   at System.Web.Http.Metadata.ModelMetadata.get_Model()
   at System.Web.Http.Validation.DefaultBodyModelValidator.ValidateNodeAndChildren(ModelMetadata metadata, ValidationContext validationContext, Object container)
   at System.Web.Http.Validation.DefaultBodyModelValidator.ValidateProperties(ModelMetadata metadata, ValidationContext validationContext)
   at System.Web.Http.Validation.DefaultBodyModelValidator.ValidateNodeAndChildren(ModelMetadata metadata, ValidationContext validationContext, Object container)
   at System.Web.Http.Validation.DefaultBodyModelValidator.ValidateProperties(ModelMetadata metadata, ValidationContext validationContext)
   at System.Web.Http.Validation.DefaultBodyModelValidator.ValidateNodeAndChildren(ModelMetadata metadata, ValidationContext validationContext, Object container)
   at System.Web.Http.Validation.DefaultBodyModelValidator.ValidateProperties(ModelMetadata metadata, ValidationContext validationContext)
   at System.Web.Http.Validation.DefaultBodyModelValidator.ValidateNodeAndChildren(ModelMetadata metadata, ValidationContext validationContext, Object container)
   at System.Web.Http.Validation.DefaultBodyModelValidator.ValidateProperties(ModelMetadata metadata, ValidationContext validationContext)
   at System.Web.Http.Validation.DefaultBodyModelValidator.ValidateNodeAndChildren(ModelMetadata metadata, ValidationContext validationContext, Object container)
   at System.Web.Http.Validation.DefaultBodyModelValidator.ValidateElements(IEnumerable model, ValidationContext validationContext)
   at System.Web.Http.Validation.DefaultBodyModelValidator.ValidateNodeAndChildren(ModelMetadata metadata, ValidationContext validationContext, Object container)
   at System.Web.Http.Validation.DefaultBodyModelValidator.ValidateProperties(ModelMetadata metadata, ValidationContext validationContext)
   at System.Web.Http.Validation.DefaultBodyModelValidator.ValidateNodeAndChildren(ModelMetadata metadata, ValidationContext validationContext, Object container)
   at System.Web.Http.Validation.DefaultBodyModelValidator.ValidateElements(IEnumerable model, ValidationContext validationContext)
   at System.Web.Http.Validation.DefaultBodyModelValidator.ValidateNodeAndChildren(ModelMetadata metadata, ValidationContext validationContext, Object container)
   at System.Web.Http.Validation.DefaultBodyModelValidator.Validate(Object model, Type type, ModelMetadataProvider metadataProvider, HttpActionContext actionContext, String keyPrefix)
   at System.Web.Http.ModelBinding.FormatterParameterBinding.<>c__DisplayClass1.<ExecuteBindingAsync>b__0(Object model)
   at System.Threading.Tasks.TaskHelpersExtensions.<>c__DisplayClass36`1.<>c__DisplayClass38.<Then>b__35()
   at System.Threading.Tasks.TaskHelpersExtensions.<>c__DisplayClass49.<ToAsyncVoidTask>b__48()
   at System.Threading.Tasks.TaskHelpers.RunSynchronously[TResult](Func`1 func, CancellationToken cancellationToken)

在玩弄了各种各样的东西之后,我完全不知所措。我知道它通常是在尝试验证属性,但是是 SqlDouble?

【问题讨论】:

    标签: entity-framework asp.net-mvc-4 asp.net-web-api json.net spatial


    【解决方案1】:

    Youssef 提到的错误已得到修复,但我在为DbGeography 创建自定义JsonConverter 时仍然遇到问题,因为在验证过程中的某处DefaultBodyModelValidator 陷入了循环。我的解决方案不是完全禁用模型验证,而是将默认验证器替换为从深度验证中排除 DbGeography 类型的派生验证器。

    为了不重复我自己,you can see the full solution here.

    【讨论】:

    • 你救了我一天的愤怒,这个 DbGeogrphy 是.... 真的是我一生中见过的毫无价值的类型。
    • 8 年后,我们仍然遇到它在我们的系统中引起的新问题。在某种程度上,我们后悔利用它。
    【解决方案2】:

    问题不在于您的转换器。这是一个已知的验证错误,当公共属性的 getter 抛出对象图中时会发生这种错误。此工作项跟踪问题:

    http://aspnetwebstack.codeplex.com/workitem/740

    与此同时,您应该能够通过禁用验证来绕过它:

    config.Services.Clear(typeof(ModelValidatorProvider));
    

    很抱歉给您带来不便。

    【讨论】:

    • 暂时的与否,至少这让我保留了一些头发在我的头上。谢谢!
    • 您可能必须使用完全限定名称:System.Web.Http.Validation.ModelValidatorProvider,如此处所述:aspnetwebstack.codeplex.com/workitem/55
    • @Youssef,请查看我的回答中的链接。我很想知道这是否是一个已知问题。
    • 真的吗?我对 MSSQL 的仇恨超过了 9000
    猜你喜欢
    • 1970-01-01
    • 2011-08-18
    • 2014-10-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-08-26
    • 2011-12-23
    相关资源
    最近更新 更多