Skip to content

Commit d611a26

Browse files
author
Adrian Hall
committed
(#149) Upgrade of OData
1 parent 058f328 commit d611a26

File tree

17 files changed

+285
-24
lines changed

17 files changed

+285
-24
lines changed

Directory.Packages.props

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,7 @@
1010
<PackageVersion Include="FluentAssertions.Web" Version="1.5.0" />
1111
<PackageVersion Include="LiteDB" Version="5.0.21" />
1212
<PackageVersion Include="Microsoft.AspNetCore.Mvc.Testing" Version="8.0.11" />
13-
<PackageVersion Include="Microsoft.AspNetCore.OData" Version="8.2.5" />
14-
<PackageVersion Include="Microsoft.Azure.Core.Spatial" Version="1.1.0" />
13+
<PackageVersion Include="Microsoft.AspNetCore.OData" Version="9.1.0" />
1514
<PackageVersion Include="Microsoft.EntityFrameworkCore" Version="8.0.11" />
1615
<PackageVersion Include="Microsoft.EntityFrameworkCore.Cosmos" Version="8.0.11" />
1716
<PackageVersion Include="Microsoft.EntityFrameworkCore.InMemory" Version="8.0.11" />
@@ -22,7 +21,7 @@
2221
<PackageVersion Include="Microsoft.Extensions.Logging.Abstractions" Version="8.0.2" />
2322
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="17.11.1" />
2423
<PackageVersion Include="Microsoft.SourceLink.GitHub" Version="8.0.0" />
25-
<PackageVersion Include="Microsoft.Spatial" Version="7.20.0" />
24+
<PackageVersion Include="Microsoft.Spatial" Version="8.2.0" />
2625
<PackageVersion Include="NSubstitute" Version="5.3.0" />
2726
<PackageVersion Include="NSwag.AspNetCore" Version="14.1.0" />
2827
<PackageVersion Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="8.0.10" />

src/CommunityToolkit.Datasync.Client/CommunityToolkit.Datasync.Client.csproj

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
<Project Sdk="Microsoft.NET.Sdk">
1+
<Project Sdk="Microsoft.NET.Sdk">
22
<PropertyGroup>
33
<Description>The client capabilities for developing applications using the Datasync Toolkit.</Description>
44
</PropertyGroup>
@@ -12,7 +12,7 @@
1212
<PackageReference Include="Microsoft.EntityFrameworkCore" />
1313
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" />
1414
<PackageReference Include="Microsoft.Extensions.Http" />
15-
<PackageReference Include="Microsoft.Azure.Core.Spatial" />
1615
<PackageReference Include="System.Threading.Tasks.Dataflow" />
16+
<PackageReference Include="Microsoft.Spatial" />
1717
</ItemGroup>
1818
</Project>

src/CommunityToolkit.Datasync.Client/Serialization/DatasyncSerializer.cs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22
// The .NET Foundation licenses this file to you under the MIT license.
33
// See the LICENSE file in the project root for more information.
44

5-
using Azure.Core.Serialization;
65
using System.Text.Json;
76
using System.Text.Json.Serialization;
87

@@ -58,7 +57,7 @@ public static string Serialize(object obj, Type objType)
5857
new DateTimeOffsetConverter(),
5958
new DateTimeConverter(),
6059
new TimeOnlyConverter(),
61-
new MicrosoftSpatialGeoJsonConverter()
60+
new SpatialGeoJsonConverter()
6261
},
6362
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingDefault,
6463
DictionaryKeyPolicy = JsonNamingPolicy.CamelCase,
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
// See the LICENSE file in the project root for more information.
4+
5+
using System.Text.Json;
6+
7+
namespace CommunityToolkit.Datasync.Client.Serialization;
8+
9+
/// <summary>
10+
/// Extension methods for System.Text.Json.
11+
/// </summary>
12+
internal static class JsonExtensions
13+
{
14+
/// <summary>
15+
/// Asserts that the current token of the <see cref="Utf8JsonReader"/> matches the <paramref name="expectedTokenType"/>.
16+
/// </summary>
17+
/// <param name="reader">The <see cref="Utf8JsonReader"/> to assert.</param>
18+
/// <param name="expectedTokenType">The expected <see cref="JsonTokenType"/> of the current token.</param>
19+
/// <exception cref="JsonException">The current token did not match the <paramref name="expectedTokenType"/>.</exception>
20+
public static void Expect(in this Utf8JsonReader reader, JsonTokenType expectedTokenType)
21+
{
22+
if (reader.TokenType != expectedTokenType)
23+
{
24+
throw new JsonException($"Deserialization failed. Expected token: '{expectedTokenType}'.");
25+
}
26+
}
27+
}
Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
// See the LICENSE file in the project root for more information.
4+
5+
using Microsoft.Spatial;
6+
using System.Text.Json;
7+
using System.Text.Json.Serialization;
8+
9+
namespace CommunityToolkit.Datasync.Client.Serialization;
10+
11+
/// <summary>
12+
/// Converters between Microsoft.Spatial types and GeoJSON
13+
/// </summary>
14+
/// <remarks>
15+
/// Only handles GeographyPoint at this time.
16+
/// </remarks>
17+
/// <see href="https://github.com/Azure/azure-sdk-for-net/tree/Microsoft.Azure.Core.Spatial_1.1.0/sdk/core/Microsoft.Azure.Core.Spatial/src/Serialization" />
18+
public class SpatialGeoJsonConverter : JsonConverter<object>
19+
{
20+
private const string CoordinatesPropertyName = "coordinates";
21+
private const string PointTypeName = "Point";
22+
private const string TypePropertyName = "type";
23+
24+
private static readonly JsonEncodedText s_CoordinatesPropertyNameBytes = JsonEncodedText.Encode(CoordinatesPropertyName);
25+
private static readonly JsonEncodedText s_TypePropertyNameBytes = JsonEncodedText.Encode(TypePropertyName);
26+
27+
/// <inheritdoc/>
28+
public override bool CanConvert(Type typeToConvert) =>
29+
typeof(GeographyPoint).IsAssignableFrom(typeToConvert);
30+
31+
/// <inheritdoc/>
32+
public override object? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
33+
{
34+
if (reader.TokenType == JsonTokenType.Null)
35+
{
36+
return null;
37+
}
38+
39+
string? type = default;
40+
double? longitude = default;
41+
double? latitude = default;
42+
43+
reader.Expect(JsonTokenType.StartObject);
44+
while (reader.Read() && reader.TokenType != JsonTokenType.EndObject)
45+
{
46+
reader.Expect(JsonTokenType.PropertyName);
47+
string? propertyName = reader.GetString();
48+
49+
_ = reader.Read();
50+
if (string.Equals(TypePropertyName, propertyName, StringComparison.Ordinal))
51+
{
52+
reader.Expect(JsonTokenType.String);
53+
type = reader.GetString();
54+
}
55+
else if (string.Equals(CoordinatesPropertyName, propertyName, StringComparison.Ordinal))
56+
{
57+
reader.Expect(JsonTokenType.StartArray);
58+
59+
// Longitude
60+
_ = reader.Read();
61+
reader.Expect(JsonTokenType.Number);
62+
longitude = reader.GetDouble();
63+
64+
// Latitude
65+
_ = reader.Read();
66+
reader.Expect(JsonTokenType.Number);
67+
latitude = reader.GetDouble();
68+
69+
// Skip the rest.
70+
do
71+
{
72+
_ = reader.Read();
73+
} while (reader.TokenType != JsonTokenType.EndArray);
74+
}
75+
else
76+
{
77+
reader.Skip();
78+
}
79+
}
80+
81+
if (!string.Equals(PointTypeName, type, StringComparison.Ordinal))
82+
{
83+
throw new JsonException($"Deserialization of {nameof(GeographyPoint)} failed. Expected geographic type: '{PointTypeName}'.");
84+
}
85+
86+
if (!longitude.HasValue || !latitude.HasValue)
87+
{
88+
throw new JsonException($"Deserialization of {nameof(GeographyPoint)} failed. Expected both longitude and latitude.");
89+
}
90+
91+
return GeographyPoint.Create(latitude.Value, longitude.Value);
92+
}
93+
94+
/// <inheritdoc/>
95+
public override void Write(Utf8JsonWriter writer, object value, JsonSerializerOptions options)
96+
{
97+
if (value is GeographyPoint point)
98+
{
99+
writer.WriteStartObject();
100+
writer.WriteString(s_TypePropertyNameBytes, PointTypeName);
101+
writer.WriteStartArray(s_CoordinatesPropertyNameBytes);
102+
writer.WriteNumberValue(point.Longitude);
103+
writer.WriteNumberValue(point.Latitude);
104+
writer.WriteEndArray();
105+
writer.WriteEndObject();
106+
}
107+
}
108+
}

src/CommunityToolkit.Datasync.Server.Abstractions/CommunityToolkit.Datasync.Server.Abstractions.csproj

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,7 @@
22
<PropertyGroup>
33
<Description>Abstractions for developing server-side applications using the Datasync Toolkit.</Description>
44
</PropertyGroup>
5-
65
<ItemGroup>
7-
<PackageReference Include="Microsoft.Azure.Core.Spatial" />
6+
<PackageReference Include="Microsoft.Spatial" />
87
</ItemGroup>
98
</Project>
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
// See the LICENSE file in the project root for more information.
4+
5+
using System.Text.Json;
6+
7+
namespace CommunityToolkit.Datasync.Server.Abstractions.Json;
8+
9+
/// <summary>
10+
/// Extension methods for System.Text.Json.
11+
/// </summary>
12+
internal static class JsonExtensions
13+
{
14+
/// <summary>
15+
/// Asserts that the current token of the <see cref="Utf8JsonReader"/> matches the <paramref name="expectedTokenType"/>.
16+
/// </summary>
17+
/// <param name="reader">The <see cref="Utf8JsonReader"/> to assert.</param>
18+
/// <param name="expectedTokenType">The expected <see cref="JsonTokenType"/> of the current token.</param>
19+
/// <exception cref="JsonException">The current token did not match the <paramref name="expectedTokenType"/>.</exception>
20+
public static void Expect(in this Utf8JsonReader reader, JsonTokenType expectedTokenType)
21+
{
22+
if (reader.TokenType != expectedTokenType)
23+
{
24+
throw new JsonException($"Deserialization failed. Expected token: '{expectedTokenType}'.");
25+
}
26+
}
27+
}
Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
// See the LICENSE file in the project root for more information.
4+
5+
using Microsoft.Spatial;
6+
using System.Text.Json;
7+
using System.Text.Json.Serialization;
8+
9+
namespace CommunityToolkit.Datasync.Server.Abstractions.Json;
10+
11+
/// <summary>
12+
/// Converters between Microsoft.Spatial types and GeoJSON
13+
/// </summary>
14+
/// <remarks>
15+
/// Only handles GeographyPoint at this time.
16+
/// </remarks>
17+
/// <see href="https://github.com/Azure/azure-sdk-for-net/tree/Microsoft.Azure.Core.Spatial_1.1.0/sdk/core/Microsoft.Azure.Core.Spatial/src/Serialization" />
18+
public class SpatialGeoJsonConverter : JsonConverter<object>
19+
{
20+
private const string CoordinatesPropertyName = "coordinates";
21+
private const string PointTypeName = "Point";
22+
private const string TypePropertyName = "type";
23+
24+
private static readonly JsonEncodedText s_CoordinatesPropertyNameBytes = JsonEncodedText.Encode(CoordinatesPropertyName);
25+
private static readonly JsonEncodedText s_TypePropertyNameBytes = JsonEncodedText.Encode(TypePropertyName);
26+
27+
/// <inheritdoc/>
28+
public override bool CanConvert(Type typeToConvert) =>
29+
typeof(GeographyPoint).IsAssignableFrom(typeToConvert);
30+
31+
/// <inheritdoc/>
32+
public override object? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
33+
{
34+
if (reader.TokenType == JsonTokenType.Null)
35+
{
36+
return null;
37+
}
38+
39+
string? type = default;
40+
double? longitude = default;
41+
double? latitude = default;
42+
43+
reader.Expect(JsonTokenType.StartObject);
44+
while (reader.Read() && reader.TokenType != JsonTokenType.EndObject)
45+
{
46+
reader.Expect(JsonTokenType.PropertyName);
47+
string? propertyName = reader.GetString();
48+
49+
_ = reader.Read();
50+
if (string.Equals(TypePropertyName, propertyName, StringComparison.Ordinal))
51+
{
52+
reader.Expect(JsonTokenType.String);
53+
type = reader.GetString();
54+
}
55+
else if (string.Equals(CoordinatesPropertyName, propertyName, StringComparison.Ordinal))
56+
{
57+
reader.Expect(JsonTokenType.StartArray);
58+
59+
// Longitude
60+
_ = reader.Read();
61+
reader.Expect(JsonTokenType.Number);
62+
longitude = reader.GetDouble();
63+
64+
// Latitude
65+
_ = reader.Read();
66+
reader.Expect(JsonTokenType.Number);
67+
latitude = reader.GetDouble();
68+
69+
// Skip the rest.
70+
do
71+
{
72+
_ = reader.Read();
73+
} while (reader.TokenType != JsonTokenType.EndArray);
74+
}
75+
else
76+
{
77+
reader.Skip();
78+
}
79+
}
80+
81+
if (!string.Equals(PointTypeName, type, StringComparison.Ordinal))
82+
{
83+
throw new JsonException($"Deserialization of {nameof(GeographyPoint)} failed. Expected geographic type: '{PointTypeName}'.");
84+
}
85+
86+
if (!longitude.HasValue || !latitude.HasValue)
87+
{
88+
throw new JsonException($"Deserialization of {nameof(GeographyPoint)} failed. Expected both longitude and latitude.");
89+
}
90+
91+
return GeographyPoint.Create(latitude.Value, longitude.Value);
92+
}
93+
94+
/// <inheritdoc/>
95+
public override void Write(Utf8JsonWriter writer, object value, JsonSerializerOptions options)
96+
{
97+
if (value is GeographyPoint point)
98+
{
99+
writer.WriteStartObject();
100+
writer.WriteString(s_TypePropertyNameBytes, PointTypeName);
101+
writer.WriteStartArray(s_CoordinatesPropertyNameBytes);
102+
writer.WriteNumberValue(point.Longitude);
103+
writer.WriteNumberValue(point.Latitude);
104+
writer.WriteEndArray();
105+
writer.WriteEndObject();
106+
}
107+
}
108+
}

src/CommunityToolkit.Datasync.Server.InMemory/DatasyncExtensions.cs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22
// The .NET Foundation licenses this file to you under the MIT license.
33
// See the LICENSE file in the project root for more information.
44

5-
using Azure.Core.Serialization;
65
using CommunityToolkit.Datasync.Server.Abstractions.Json;
76
using System.Text.Json;
87
using System.Text.Json.Serialization;
@@ -32,7 +31,7 @@ public static TEntity Clone<TEntity>(this TEntity entity)
3231
new DateTimeOffsetConverter(),
3332
new DateTimeConverter(),
3433
new TimeOnlyConverter(),
35-
new MicrosoftSpatialGeoJsonConverter()
34+
new SpatialGeoJsonConverter()
3635
},
3736
DefaultIgnoreCondition = JsonIgnoreCondition.Never,
3837
DictionaryKeyPolicy = JsonNamingPolicy.CamelCase,

src/CommunityToolkit.Datasync.Server/CommunityToolkit.Datasync.Server.csproj

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@
1313

1414
<ItemGroup>
1515
<PackageReference Include="Microsoft.AspNetCore.OData" />
16-
<PackageReference Include="Microsoft.Azure.Core.Spatial" />
1716
</ItemGroup>
1817

1918
<ItemGroup>

0 commit comments

Comments
 (0)