.NET 8中使用System.Text.Json序列化空间点失败问题排查
问题
在Blazor 8服务端应用中序列化EF模型中的空间点字段CurrentHabitat.SiteLocation时失败。该字段对应MSSQL数据库的(geography,null)类型,模型是通过反向工程生成的。
序列化代码
var options = new JsonSerializerOptions { Converters = { new MicrosoftSpatialGeoJsonConverter() }, NumberHandling = System.Text.Json.Serialization.JsonNumberHandling.AllowNamedFloatingPointLiterals, ReferenceHandler = ReferenceHandler.Preserve, MaxDepth=100 }; string thisLatLong = JsonSerializer.Serialize(CurrentHabitat.SiteLocation,options);
字段值详情
{POINT (-3.89695 55.99762)} Area: 0 Boundary: {GEOMETRYCOLLECTION EMPTY} BoundaryDimension: False Centroid: {POINT (-3.89695 55.99762)} Coordinate: {(-3.89695, 55.99762)} CoordinateSequence: {((-3.89695, 55.99762))} Coordinates: {NetTopologySuite.Geometries.Coordinate[1]} Dimension: P Envelope: {POINT (-3.89695 55.99762)} EnvelopeInternal: {Env[-3.89695 : -3.89695, 55.99762 : 55.99762]} Factory: {GeometryFactory[PM=Floating, SRID=4326, CSFactory=CoordinateArraySequenceFactory, GeometryOverlay:Legacy]} GeometryType: "Point" InteriorPoint: {POINT (-3.89695 55.99762)} IsEmpty: false IsGeometryCollection: false IsRectangle: false IsSimple: true IsValid: true Length: 0 M: NaN NumGeometries: 1 NumPoints: 1 OgcGeometryType: Point PointOnSurface: {POINT (-3.89695 55.99762)} PrecisionModel: {Floating} SRID: 4326 SortIndex: Point UserData: null X: -3.89695 Y: 55.99762 Z: NaN
错误信息
{"Specified argument was out of the range of valid values. (Parameter 'X called on empty Point')"}
堆栈跟踪
at NetTopologySuite.Geometries.Point.get_X() at System.Text.Json.Serialization.Metadata.JsonPropertyInfo`1.GetMemberAndWriteJson(Object obj, WriteStack& state, Utf8JsonWriter writer) at System.Text.Json.Serialization.Converters.ObjectDefaultConverter`1.OnTryWrite(Utf8JsonWriter writer, T value, JsonSerializerOptions options, WriteStack& state) at System.Text.Json.Serialization.JsonConverter`1.TryWrite(Utf8JsonWriter writer, T& value, JsonSerializerOptions options, WriteStack& state) at System.Text.Json.Serialization.Metadata.JsonPropertyInfo`1.GetMemberAndWriteJson(Object obj, WriteStack& state, Utf8JsonWriter writer) at System.Text.Json.Serialization.Converters.ObjectDefaultConverter`1.OnTryWrite(Utf8JsonWriter writer, T value, JsonSerializerOptions options, WriteStack& state) at System.Text.Json.Serialization.JsonConverter`1.TryWrite(Utf8JsonWriter writer, T& value, JsonSerializerOptions options, WriteStack& state) at System.Text.Json.Serialization.Metadata.JsonPropertyInfo`1.GetMemberAndWriteJson(Object obj, WriteStack& state, Utf8JsonWriter writer) at System.Text.Json.Serialization.Converters.ObjectDefaultConverter`1.OnTryWrite(Utf8JsonWriter writer, T value, JsonSerializerOptions options, WriteStack& state) at System.Text.Json.Serialization.JsonConverter`1.TryWrite(Utf8JsonWriter writer, T& value, JsonSerializerOptions options, WriteStack& state) at System.Text.Json.Serialization.Metadata.JsonPropertyInfo`1.GetMemberAndWriteJson(Object obj, WriteStack& state, Utf8JsonWriter writer) at System.Text.Json.Serialization.Converters.ObjectDefaultConverter`1.OnTryWrite(Utf8JsonWriter writer, T value, JsonSerializerOptions options, WriteStack& state) at System.Text.Json.Serialization.JsonConverter`1.TryWrite(Utf8JsonWriter writer, T& value, JsonSerializerOptions options, WriteStack& state) at System.Text.Json.Serialization.JsonConverter`1.WriteCore(Utf8JsonWriter writer, T& value, JsonSerializerOptions options, WriteStack& state) at System.Text.Json.Serialization.Metadata.JsonTypeInfo`1.Serialize(Utf8JsonWriter writer, T& rootValue, Object rootValueBoxed) at System.Text.Json.JsonSerializer.WriteString[TValue](TValue& value, JsonTypeInfo`1 jsonTypeInfo) at System.Text.Json.JsonSerializer.Serialize[TValue](TValue value, JsonSerializerOptions options) at HabitatHub3.Pages.ShowPond.<onSaveClick>d__42.MoveNext() in C:\Users\Blahblah\source\repos\HabitatHub3\HabitatHub3\Pages\ShowPond.razor:line 371
解决方案
问题根源
你使用的MicrosoftSpatialGeoJsonConverter是针对Microsoft.Spatial类型(如DbGeography)设计的,但你的SiteLocation实际是NetTopologySuite(NTS)的Point类型,两者不兼容。序列化时JsonSerializer会尝试用默认转换器处理对象的嵌套属性(比如Boundary这个空的GeometryCollection),访问其内部空Point的X属性时触发错误。
修复步骤
替换为NTS专属的Json转换器
先安装NetTopologySuite的Json序列化包:NetTopologySuite.IO.JsonSystemTextJson
然后修改序列化配置:using NetTopologySuite.IO; var options = new JsonSerializerOptions { Converters = { new GeoJsonConverterFactory() }, NumberHandling = System.Text.Json.Serialization.JsonNumberHandling.AllowNamedFloatingPointLiterals, ReferenceHandler = ReferenceHandler.Preserve, MaxDepth=100 }; string thisLatLong = JsonSerializer.Serialize(CurrentHabitat.SiteLocation, options);直接提取坐标序列化(临时方案)
若只需要坐标值,可跳过完整对象序列化,直接输出符合GeoJSON格式的字符串:string thisLatLong = $"{{\"type\":\"Point\",\"coordinates\":[{CurrentHabitat.SiteLocation.X},{CurrentHabitat.SiteLocation.Y}]}}";排除空属性序列化(可选)
如果不想替换转换器,可在JsonSerializerOptions中添加DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull,或给NTS类型的空属性手动添加[JsonIgnore]特性,但这种方法可靠性较低,仍可能触发内部属性访问错误。
内容的提问来源于stack exchange,提问作者Martin
相关产品推荐
相关产品推荐

