entity-framework - 用于 DbGeography 的 JSON.Net JsonConverter

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

长期与这个斗争...

基本上我有一个模型优先的 EF5 对象,它带有 DbGeography属性(property)。我想申请 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?

最佳答案

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

以免重复我自己,you can see the full solution here.

关于entity-framework - 用于 DbGeography 的 JSON.Net JsonConverter,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14147299/

相关文章:

asp.net-web-api - 停止验证 Azure AD 中 Web api 应用程序的受众

mysql - 定义具有多对多关系的两个实体之间的关系

asp.net-mvc - 使用 EF 6 和 MVC 5 中的代码优先方法将新表添加到现有数据库

c# - 如何从 json 操作中获取数据到 View 中

c# - 调用 mvc 异步方法的 ajax 调用永远不会返回

c# - 使用 NEST 索引动态对象

asp.net-web-api - 具有通配符名称的基于 asp.net 角色的授权

NHibernate 等效于 Entity Framework DbSet.Local 用于未刷新的实体?

database - 为什么 Entity Framework 类需要不相关类的虚拟成员

c# - 如何使用 ASP.Net MVC 根据需要动态设置字段?