我尝试在数据库SQL Server 2012中使用Newtonsoft.Json版本'Newtonsoft.Json.10.0.3'将 DataTable
对象序列化为Json .
该表有一个类型为'geography'的列,其中包含SqlGeography类型的实例 .
用于生成json的代码:
public string SerializeToJson()
{
var connstring1 ="Data Source=server1;Initial Catalog=database1;user=xxx;password=yyy";
var sql = "SELECT * FROM table_1 "; //table_1 has a column of type geography
using (var c1 = new SqlConnection(connstring1))
{
c1.Open();
var da = new SqlDataAdapter()
{
SelectCommand = new SqlCommand(sql, c1)
};
DataSet ds1 = new DataSet("table");
da.Fill(ds1, "table");
var dt = ds1.Tables[0];
//serialize to Json
try
{
var options = new JsonSerializerSettings
{
Formatting = Formatting.None
};
//this line fire exception for geography type
var json = JsonConvert.SerializeObject(dt, options);
return json;
}
catch (Exception ex)
{
Console.WriteLine(ex);
}
}
}
我已经从sql 2012的功能包安装了程序集“Microsoft.SqlServer.Types”
我创建了一个完整的C#程序(独立于sql server安装),使用带有SqlGeography列的数据表来显示问题Try it
我收到错误:
Newtonsoft.Json.JsonSerializationException:从'System.Data.SqlTypes.SqlDouble'上的'Value'获取值时出错 . ---> System.Data.SqlTypes.SqlNullValueException:数据为空 . 无法在Null值上调用此方法或属性 . 在Newtonsoft.Json.Serialization.DynamicValueProvider.GetValue(对象目标)的GetValue(Object)处的System.Data.SqlTypes.SqlDouble.get_Value()处
我达到了https://github.com/JamesNK/Newtonsoft.Json/issues/993,但它无能为力 .
任何帮助解决问题 .
Edit:
基于@dbc注释,我提供了用于生成json的完整源代码 .
完整的错误消息是:
Newtonsoft.Json.JsonSerializationException:从'System.Data.SqlTypes.SqlDouble'上的'Value'获取值时出错 . --- >> System.Data.SqlTypes.SqlNullValueException:数据为空 . 无法在Null值上调用此方法或属性 . 在Newtonoft.Json.Serialization.DynamicValueProvider.GetValue(对象目标)的GetValue(Object)处的System.Data.SqlTypes.SqlDouble.get_Value()---内部异常堆栈跟踪的结束---在Newtonsoft.Json.Serialization处 . Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.SerializeObject(Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.CalculatePropertyValues(JsonWriter writer,Object value,JsonContainerContract contract,JsonProperty member,JsonProperty property,JsonContract&memberContract,Object&memberValue)中的DynamicValueProvider.GetValue(Object target)在Newtonsoft的Newtonoft.Json.Serialization.JsonSerializerInternalWriter.SerializeValue(JsonWriter writer,Object value,JsonContract valueContract,JsonProperty成员,JsonContainerContract containerContract,JsonProperty containerProperty)中的JsonWriter编写器,Object值,JsonObjectContract Contract ,JsonProperty成员,JsonContainerContract collectionContract,JsonProperty containerProperty) . JSON .Serialization.JerialSerializerInternalWriter.SerializeObject(JsonWriter writer,Object value,JsonObjectContract contract,JsonProperty member,JsonContainerContract collectionContract,JsonProperty containerProperty)at Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.SerializeValue(JsonWriter writer,Object value,JsonContract valueContract,JsonProperty member,JsonContainerContract containerContract ,JunesProperty containerProperty)Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.Serialize(JsonWriter jsonWriter,Object value,Type objectType)at Newtonsoft.Json.Serialization.JsonSerializerProxy.SerializeInternal(JsonWriter jsonWriter,Object value,Type rootType)at Newtonsoft.Json.Converters NewPathoft.Json.Serialization.JsonSerializerInternalWriter.SerializeConver表中的.DataTableConverter.WriteJson(JsonWriter writer,Object value,JsonSerializer serializer)(JsonWriter writer,JsonConverter转换器,Object值,JsonContract Contract ,JsonContainerCo) ntract collectionContract,JsonProperty containerProperty)at Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.SerializeValue(JsonWriter writer,Object value,JsonContract valueContract,JsonProperty member,JsonContainerContract containerContract,JsonProperty containerProperty)at Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.Serialize(JsonWriter jsonWriter,Object在Newtonsoft.Json.Json.Ivson.Serialize对象中的Newtonsoft.Json.JsonSerializer.SerializeInternal(JsonWriter jsonWriter,Object value,Type objectType)的Newtonsoft.Json.JsonConvert.SerializeObjectInternal(Object value,Type type,JsonSerializer jsonSerializer)中的值,类型objectType)(对象值,JsonSerializerSettings设置)在F:\ JsonTester.cs中的JsonTester.SerializeToJson():第104行
Edit2:
我按@dbc的描述启用跟踪,并获取以下日志:
2017-08-24T19:45:31.941 Info已开始使用转换器序列化System.Data.DataTableNewtonsoft.Json.Converters.DataTableConverter . 路径'' . 2017-08-24T19:45:31.972 Info已开始序列化Microsoft.SqlServer.Types.SqlGeography . 路径'[0] .f1' . 2017-08-24T19:45:32.003 Info已开始序列化System.Data.SqlTypes.SqlInt32.Path'[0] .f1.STSrid' . 2017-08-24T19:45:32.003 Info完成序列化System.Data.SqlTypes.SqlInt32 . 路径'[0] .f1.STSrid' . 2017-08-24T19:45:32.003 Info已开始序列化System.Data.SqlTypes.SqlDouble . 路径'[0] .f1.Lat' . 2017-08-24T19:45:32.003 Info完成序列化System.Data.SqlTypes.SqlDouble . 路径'[0] .f1.Lat' . 2017-08-24T19:45:32.003 Info已开始序列化System.Data.SqlTypes.SqlDouble . 路径'[0] .f1.Long' . 2017-08-24T19:45:32.003 Info完成序列化System.Data.SqlTypes.SqlDouble . 路径'[0] .f1.Long' . 2017-08-24T19:45:32.003 Info已开始序列化System.Data.SqlTypes.SqlDouble . 路径'[0] .f1.Z' . 2017-08-24T19:45:32.003错误序列化System.Data.SqlTypes.SqlDouble.Error从'System.Data.SqlTypes.SqlDouble'上的'Value'获取值时出错 . 2017-08-24T19:45:32.003错误序列化System.Data.DataTable时出错 . 从'System.Data.SqlTypes.SqlDouble'上的'Value'获取值时出错 .
1 回答
看起来像
System.Data.SqlTypes
的SqlDouble
这样的原始类型无法通过Json.NET进行开箱即用,因为它们没有实现自己的TypeConverter
. 来自docs:这有必要实现custom JsonConverter来序列化这些类型 . 对于内置的.Net类型,Json.NET有几个内置的converters,例如KeyValuePairConverter,所以这并不罕见 .
SqlBoolean
,SqlBinary
,SqlDouble
等不共享公共基类或除INullable之外的接口这一事实需要一些重复的代码:工作.Net fiddle从您的own分叉 .
如果需要反序列化由此创建的JSON,则还有两个问题 . 首先,SqlGeography的某些属性(例如Lat和Long)是get-only . 您需要创建自定义
JsonConverter
才能完全反序列化此类型 .其次,Json.NET无法将具有行值的复杂对象的JSON反序列化为无类型的
DataTable
. 因此,如果需要反序列化包含复杂对象的JSON(例如序列化的SqlGeography
),则可以使用以下选项:创建并反序列化为类型
DataTable
.直接使用
DataTableConverter
使用预先分配的列填充预先存在的DataTable
,如here所示 .反序列化为DTOs列表,如下所示:
其中
SqlGeographyConverter
根据需要为SqlGeography
自定义JsonConverter
.然后做: