-
Notifications
You must be signed in to change notification settings - Fork 481
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
LINQ: Add support for System.Text.Json attributes #3250
Comments
You can supply |
Hi all, we've merged what we hope will be a solution to this issue by allowing the custom serializer to be used for LINQ translations. This also unblocks having System.Text.Json attributes applied in LINQ queries. We plan to release this as part of the next preview package, but I also wanted to take this time to confirm these changes meet your needs before finalizing them as part of our public API. If you try the changes out, please follow up in the thread if this update addresses your concerns. If it doesn't, please let us know why. To use your own custom serializer for LINQ translations you must implement |
@Maya-Painter, that is good news! When is this preview package available on NuGet? If we register a custom serializer in CosmosClientOptions will this also be implemented by the CosmosLinqSerializer? For example if we do it like this: Custom serializator class: public sealed class CosmosSystemTextJsonSerializer : CosmosSerializer, CosmosLinqSerializer
{
private readonly JsonObjectSerializer _systemTextJsonSerializer;
public CosmosSystemTextJsonSerializer(JsonSerializerOptions jsonSerializerOptions)
{
_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)_systemTextJsonSerializer.Deserialize(stream, typeof(T), default);
}
}
public override Stream ToStream<T>(T input)
{
var streamPayload = new MemoryStream();
_systemTextJsonSerializer.Serialize(streamPayload, input, typeof(T), default);
streamPayload.Position = 0;
return streamPayload;
}
} and then register it like so for example: CosmosClientOptions cosmosClientOptions = new()
{
...
Serializer = new CosmosSystemTextJsonSerializer(new JsonSerializerOptions()
{
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull,
Converters =
{
new JsonStringEnumConverter()
}
})
}; |
@machie27 CosmosLinqSerializer is inaccessible due to its protection level, its internal class and can't be inherited. |
Hi @v-mghabin, Sorry I've mentioned this in another request as well and got a response there from @Maya-Painter. This isn't the way it should be implemented indeed. Link to which I'm referring to: link please note that in this example I also convert the membernames by setting the policy naming explicitly. I've an example here: public class CosmosSystemTextJsonSerializer : CosmosLinqSerializer
{
private readonly JsonObjectSerializer _systemTextJsonSerializer;
public CosmosSystemTextJsonSerializer(JsonSerializerOptions jsonSerializerOptions)
{
_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)_systemTextJsonSerializer.Deserialize(stream, typeof(T), default);
}
}
public override string SerializeMemberName(MemberInfo memberInfo)
{
var jsonPropertyNameAttribute = memberInfo.GetCustomAttribute<JsonPropertyNameAttribute>(true);
string memberName = !string.IsNullOrEmpty(jsonPropertyNameAttribute?.Name)
? jsonPropertyNameAttribute.Name
: memberInfo.Name;
return JsonNamingPolicy.CamelCase.ConvertName(memberName);
}
public override Stream ToStream<T>(T input)
{
var streamPayload = new MemoryStream();
_systemTextJsonSerializer.Serialize(streamPayload, input, typeof(T), default);
streamPayload.Position = 0;
return streamPayload;
}
} |
If you follow this sample and use the System.Text.Json as the default serializer LINQ will not translate the attribute so the incorrect query will be generated. This will cause the query to return no or incorrect results.
Follow the sample listed here: https://github.com/Azure/azure-cosmos-dotnet-v3/blob/master/Microsoft.Azure.Cosmos.Samples/Usage/SystemTextJson/CosmosSystemTextJsonSerializer.cs
Update the class like the sample:
Try to do a LINQ query:
The query will execute but it will return no results because it will be translated as 'PoolId' instead of the expected 'poolId'.
It seems the following code needs to be updated to handle the new System.Text.Json types:
azure-cosmos-dotnet-v3/Microsoft.Azure.Cosmos/src/Linq/TypeSystem.cs
Line 30 in cee34ce
The text was updated successfully, but these errors were encountered: