Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Samples: Adds STJ LINQ Serializer Example #4420

Merged
Original file line number Diff line number Diff line change
@@ -1,21 +1,25 @@
namespace Cosmos.Samples.Shared
{
using System.IO;
using System.Reflection;
using System.Text.Json;
using System.Text.Json.Serialization;
using Azure.Core.Serialization;
using Microsoft.Azure.Cosmos;

/// <summary>
/// Uses <see cref="Azure.Core.Serialization.JsonObjectSerializer"/> which leverages System.Text.Json providing a simple API to interact with on the Azure SDKs.
/// </summary>
// <SystemTextJsonSerializer>
public class CosmosSystemTextJsonSerializer : CosmosSerializer
public class CosmosSystemTextJsonSerializer : CosmosLinqSerializer
{
private readonly JsonObjectSerializer systemTextJsonSerializer;
private readonly JsonSerializerOptions jsonSerializerOptions;

public CosmosSystemTextJsonSerializer(JsonSerializerOptions jsonSerializerOptions)
{
this.systemTextJsonSerializer = new JsonObjectSerializer(jsonSerializerOptions);
this.jsonSerializerOptions = jsonSerializerOptions;
}

public override T FromStream<T>(Stream stream)
Expand Down Expand Up @@ -44,6 +48,30 @@ public override Stream ToStream<T>(T input)
streamPayload.Position = 0;
return streamPayload;
}

public override string SerializeMemberName(MemberInfo memberInfo)
ealsur marked this conversation as resolved.
Show resolved Hide resolved
{
JsonExtensionDataAttribute jsonExtensionDataAttribute = memberInfo.GetCustomAttribute<JsonExtensionDataAttribute>(true);
if (jsonExtensionDataAttribute != null)
{
return null;
}

JsonPropertyNameAttribute jsonPropertyNameAttribute = memberInfo.GetCustomAttribute<JsonPropertyNameAttribute>(true);
if (!string.IsNullOrEmpty(jsonPropertyNameAttribute?.Name))
{
return jsonPropertyNameAttribute.Name;
}

if (this.jsonSerializerOptions.PropertyNamingPolicy != null)
{
return this.jsonSerializerOptions.PropertyNamingPolicy.ConvertName(memberInfo.Name);
}

// Do any additional handling of JsonSerializerOptions here.

return memberInfo.Name;
}
}
// </SystemTextJsonSerializer>
}
Original file line number Diff line number Diff line change
Expand Up @@ -115,8 +115,6 @@ private static async Task RunDemo()
Console.WriteLine($"Created Completed activity with id {createCompletedActivity.Resource.Id} that cost {createCompletedActivity.RequestCharge}");

// Execute queries materializing responses using System.Text.Json
// NOTE: GetItemLinqQueryable does not support System.Text.Json attributes. LINQ will not translate the name based on the attributes
Maya-Painter marked this conversation as resolved.
Show resolved Hide resolved
// which can result in no or invalid results coming back. https://github.com/Azure/azure-cosmos-dotnet-v3/issues/3250
using FeedIterator<ToDoActivity> iterator = container.GetItemQueryIterator<ToDoActivity>("select * from c where c.status = 'Completed'");
while (iterator.HasMoreResults)
{
Expand Down Expand Up @@ -177,19 +175,15 @@ private static async Task CleanupAsync()
// <Model>
public class ToDoActivity
{
// Note: System.Text.Json attributes such as JsonPropertyName are currently applied on item CRUD operations and non-LINQ queries, but not on LINQ queries
Maya-Painter marked this conversation as resolved.
Show resolved Hide resolved
[JsonPropertyName("id")]
public string Id { get; set; }

// Note: System.Text.Json attributes such as JsonPropertyName are currently applied on item CRUD operations and non-LINQ queries, but not on LINQ queries
[JsonPropertyName("partitionKey")]
public string PartitionKey { get; set; }

// Note: System.Text.Json attributes such as JsonPropertyName are currently applied on item CRUD operations and non-LINQ queries, but not on LINQ queries
[JsonPropertyName("activityId")]
public string ActivityId { get; set; }

// Note: System.Text.Json attributes such as JsonPropertyName are currently applied on item CRUD operations and non-LINQ queries, but not on LINQ queries
[JsonPropertyName("status")]
public string Status { get; set; }
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
<PackageReference Include="Microsoft.Extensions.Configuration.FileExtensions" Version="2.2.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="2.2.0" />
<PackageReference Include="System.Text.Json" Version="5.0.2" />
<PackageReference Include="Microsoft.Azure.Cosmos" Version="*" />
<PackageReference Include="Microsoft.Azure.Cosmos" Version="3.39.0" />
Maya-Painter marked this conversation as resolved.
Show resolved Hide resolved
</ItemGroup>
<ItemGroup>
<None Include="..\AppSettings.json">
Expand Down
71 changes: 4 additions & 67 deletions Microsoft.Azure.Cosmos/src/Serializer/CosmosLinqSerializer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,73 +8,10 @@ namespace Microsoft.Azure.Cosmos
/// <summary>
/// This abstract class can be implemented to allow a custom serializer (Non [Json.NET serializer](https://www.newtonsoft.com/json/help/html/Introduction.htm)'s)
/// to be used by the CosmosClient for LINQ queries.
/// </summary>
/// <example>
/// This example implements the CosmosLinqSerializer contract.
/// This example custom serializer will honor System.Text.Json attributes.
/// <code language="c#">
/// <![CDATA[
/// class SystemTextJsonSerializer : CosmosLinqSerializer
/// {
/// private readonly JsonObjectSerializer systemTextJsonSerializer;
///
/// public SystemTextJsonSerializer(JsonSerializerOptions jsonSerializerOptions)
/// {
/// this.systemTextJsonSerializer = new JsonObjectSerializer(jsonSerializerOptions);
/// }
///
/// public override T FromStream<T>(Stream stream)
/// {
/// if (stream == null)
/// throw new ArgumentNullException(nameof(stream));
///
/// using (stream)
/// {
/// if (stream.CanSeek && stream.Length == 0)
/// {
/// return default;
/// }
///
/// if (typeof(Stream).IsAssignableFrom(typeof(T)))
/// {
/// return (T)(object)stream;
/// }
///
/// return (T)this.systemTextJsonSerializer.Deserialize(stream, typeof(T), default);
/// }
/// }
///
/// public override Stream ToStream<T>(T input)
/// {
/// MemoryStream streamPayload = new MemoryStream();
/// this.systemTextJsonSerializer.Serialize(streamPayload, input, input.GetType(), default);
/// streamPayload.Position = 0;
/// return streamPayload;
/// }
///
/// public override string SerializeMemberName(MemberInfo memberInfo)
/// {
/// System.Text.Json.Serialization.JsonExtensionDataAttribute jsonExtensionDataAttribute =
/// memberInfo.GetCustomAttribute<System.Text.Json.Serialization.JsonExtensionDataAttribute>(true);
/// if (jsonExtensionDataAttribute != null)
/// {
/// return null;
/// }
///
/// JsonPropertyNameAttribute jsonPropertyNameAttribute = memberInfo.GetCustomAttribute<JsonPropertyNameAttribute>(true);
///
/// string memberName = !string.IsNullOrEmpty(jsonPropertyNameAttribute?.Name)
/// ? jsonPropertyNameAttribute.Name
/// : memberInfo.Name;
///
/// // Users must add handling for any additional attributes here
///
/// return memberName;
/// }
/// }
/// ]]>
/// </code>
/// </example>
/// </summary>
/// <remarks>
/// https://github.com/Azure/azure-cosmos-dotnet-v3/blob/master/Microsoft.Azure.Cosmos.Samples/Usage/SystemTextJson/CosmosSystemTextJsonSerializer.cs
Maya-Painter marked this conversation as resolved.
Show resolved Hide resolved
/// </remarks>
public abstract class CosmosLinqSerializer : CosmosSerializer
{
/// <summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -836,11 +836,13 @@ public override void SerializeAsXml(XmlWriter xmlWriter)

class SystemTextJsonLinqSerializer : CosmosLinqSerializer
{
private readonly JsonObjectSerializer systemTextJsonSerializer;
private readonly JsonObjectSerializer systemTextJsonSerializer;
private readonly JsonSerializerOptions jsonSerializerOptions;

public SystemTextJsonLinqSerializer(JsonSerializerOptions jsonSerializerOptions)
{
this.systemTextJsonSerializer = new JsonObjectSerializer(jsonSerializerOptions);
this.systemTextJsonSerializer = new JsonObjectSerializer(jsonSerializerOptions);
this.jsonSerializerOptions = jsonSerializerOptions;
}

public override T FromStream<T>(Stream stream)
Expand Down Expand Up @@ -882,12 +884,19 @@ public override string SerializeMemberName(MemberInfo memberInfo)
}

JsonPropertyNameAttribute jsonPropertyNameAttribute = memberInfo.GetCustomAttribute<JsonPropertyNameAttribute>(true);

string memberName = !string.IsNullOrEmpty(jsonPropertyNameAttribute?.Name)
? jsonPropertyNameAttribute.Name
: memberInfo.Name;

return memberName;
if (!string.IsNullOrEmpty(jsonPropertyNameAttribute?.Name))
{
return jsonPropertyNameAttribute.Name;
}

if (this.jsonSerializerOptions.PropertyNamingPolicy != null)
{
return this.jsonSerializerOptions.PropertyNamingPolicy.ConvertName(memberInfo.Name);
}

// Do any additional handling of JsonSerializerOptions here.

return memberInfo.Name;
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -198,7 +198,7 @@ class TestCustomJsonLinqSerializer : CosmosLinqSerializer
{
private readonly JsonObjectSerializer systemTextJsonSerializer;

public static readonly System.Text.Json.JsonSerializerOptions JsonOptions = new()
private readonly System.Text.Json.JsonSerializerOptions jsonSerializerOptions = new()
{
DefaultIgnoreCondition = System.Text.Json.Serialization.JsonIgnoreCondition.WhenWritingNull,
PropertyNameCaseInsensitive = true,
Expand All @@ -209,7 +209,7 @@ class TestCustomJsonLinqSerializer : CosmosLinqSerializer

public TestCustomJsonLinqSerializer()
{
this.systemTextJsonSerializer = new JsonObjectSerializer(JsonOptions);
this.systemTextJsonSerializer = new JsonObjectSerializer(this.jsonSerializerOptions);
}

public override T FromStream<T>(Stream stream)
Expand Down Expand Up @@ -237,24 +237,31 @@ public override Stream ToStream<T>(T input)
this.systemTextJsonSerializer.Serialize(stream, input, input.GetType(), default);
stream.Position = 0;
return stream;
}

public override string SerializeMemberName(MemberInfo memberInfo)
}
public override string SerializeMemberName(MemberInfo memberInfo)
{
System.Text.Json.Serialization.JsonExtensionDataAttribute jsonExtensionDataAttribute =
memberInfo.GetCustomAttribute<System.Text.Json.Serialization.JsonExtensionDataAttribute>(true);
if (jsonExtensionDataAttribute != null)
{
return null;
}

JsonPropertyNameAttribute jsonPropertyNameAttribute = memberInfo.GetCustomAttribute<JsonPropertyNameAttribute>(true);

string memberName = jsonPropertyNameAttribute != null && !string.IsNullOrEmpty(jsonPropertyNameAttribute.Name)
? jsonPropertyNameAttribute.Name
: memberInfo.Name;

return memberName;

JsonPropertyNameAttribute jsonPropertyNameAttribute = memberInfo.GetCustomAttribute<JsonPropertyNameAttribute>(true);
if (!string.IsNullOrEmpty(jsonPropertyNameAttribute?.Name))
{
return jsonPropertyNameAttribute.Name;
}

if (this.jsonSerializerOptions.PropertyNamingPolicy != null)
{
return this.jsonSerializerOptions.PropertyNamingPolicy.ConvertName(memberInfo.Name);
}

// Do any additional handling of JsonSerializerOptions here.

return memberInfo.Name;
}
}

Expand Down
Loading