question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Add async methods to CosmosSerializer

See original GitHub issue

Is your feature request related to a problem? Please describe. Currently CosmosSerializer only has synchronous methods.

In order to create a custom serializer that uses the new JsonSerializer in .NET Core 3, async methods should be added to CosmosSerializer. The default implementation can just call the synchronous methods to support backwards compatibility.

Describe the solution you’d like

//------------------------------------------------------------
// Copyright (c) Microsoft Corporation.  All rights reserved.
//------------------------------------------------------------

namespace Microsoft.Azure.Cosmos
{
    using System;
    using System.IO;
    using System.Threading;
    using System.Threading.Tasks;

    /// <summary>
    /// This is an interface to allow a custom serializer to be used by the CosmosClient
    /// </summary>
    public abstract class CosmosSerializer
    {
        /// <summary>
        /// Convert a Stream of JSON to an object. 
        /// The caller will ensure the stream is disposed. 
        /// This will prevent memory leaks if an exception is hit.
        /// </summary>
        /// <typeparam name="T">Any typed passed to <see cref="Container"/></typeparam>
        /// <param name="stream">The Stream response containing JSON from Cosmos</param>
        /// <returns>The object deserialized from the stream.</returns>
        public abstract T FromStream<T>(Stream stream);

        /// <summary>
        /// Convert the object to a Stream. 
        /// The caller will take ownership of the stream and ensure it is correctly disposed of.
        /// Stream.CanRead must be true https://docs.microsoft.com/dotnet/api/system.io.stream.canread?view=netcore-2.0
        /// </summary>
        /// <param name="input">Any typed passed to <see cref="Container"/></param>
        /// <returns>A readable Stream containing JSON of the serialized object</returns>
        public abstract Stream ToStream<T>(T input);

        /// <summary>
        /// Convert a Stream of JSON to an object. 
        /// The caller will ensure the stream is disposed. 
        /// This will prevent memory leaks if an exception is hit.
        /// </summary>
        /// <typeparam name="T">Any typed passed to <see cref="Container"/></typeparam>
        /// <param name="stream">The Stream response containing JSON from Cosmos</param>
        /// <param name="cancellationToken"></param>
        /// <returns>The object deserialized from the stream.</returns>
        public virtual ValueTask<T> FromStreamAsync<T>(Stream stream, CancellationToken cancellationToken = default)
        {
            try
            {
                return new ValueTask<T>(this.FromStream<T>(stream));
            }
            catch (Exception ex)
            {
                return new ValueTask<T>(Task.FromException<T>(ex));
            }
        }

        /// <summary>
        /// Convert the object to a Stream. 
        /// The caller will take ownership of the stream and ensure it is correctly disposed of.
        /// Stream.CanRead must be true https://docs.microsoft.com/dotnet/api/system.io.stream.canread?view=netcore-2.0
        /// </summary>
        /// <param name="input">Any typed passed to <see cref="Container"/></param>
        /// <param name="cancellationToken"></param>
        /// <returns>A readable Stream containing JSON of the serialized object</returns>
        public virtual ValueTask<Stream> ToStreamAsync<T>(T input, CancellationToken cancellationToken = default)
        {
            try
            {
                return new ValueTask<Stream>(this.ToStream(input));
            }
            catch (Exception ex)
            {
                return new ValueTask<Stream>(Task.FromException<Stream>(ex));
            }
        }
    }
}

Issue Analytics

  • State:closed
  • Created 4 years ago
  • Reactions:3
  • Comments:7 (2 by maintainers)

github_iconTop GitHub Comments

2reactions
martincostellocommented, Aug 17, 2019

+1 to this. I’ve just updated an application to use the v3 Cosmos SDK, and then subsequently run into this while updating the branch of the app using ASP.NET Core 3.0 preview 8.

In the meantime, I came up with this implementation that uses the synchronous APIs for System.Text.Json.

using System.IO;
using System.Text.Json;
using Microsoft.Azure.Cosmos;

namespace MyApp
{
    public class SystemTextJsonCosmosSerializer : CosmosSerializer
    {
        private readonly JsonSerializerOptions _options;

        public SystemTextJsonCosmosSerializer(JsonSerializerOptions options)
        {
            _options = options;
        }

        /// <inheritdoc />
        public override T FromStream<T>(Stream stream)
        {
            // Have to dispose of the stream, otherwise the Cosmos SDK throws.
            // https://github.com/Azure/azure-cosmos-dotnet-v3/blob/0843cae3c252dd49aa8e392623d7eaaed7eb712b/Microsoft.Azure.Cosmos/src/Serializer/CosmosJsonSerializerWrapper.cs#L22
            // https://github.com/Azure/azure-cosmos-dotnet-v3/blob/0843cae3c252dd49aa8e392623d7eaaed7eb712b/Microsoft.Azure.Cosmos/src/Serializer/CosmosJsonDotNetSerializer.cs#L73
            using (stream)
            {
                // TODO Would be more efficient if CosmosSerializer supported async
                using var memory = new MemoryStream((int)stream.Length);
                stream.CopyTo(memory);

                byte[] utf8Json = memory.ToArray();

                return JsonSerializer.Deserialize<T>(utf8Json, _options);
            }
        }

        /// <inheritdoc />
        public override Stream ToStream<T>(T input)
        {
            byte[] utf8Json = JsonSerializer.SerializeToUtf8Bytes(input, _options);
            return new MemoryStream(utf8Json);
        }
    }
}
0reactions
ankitvijaycommented, Aug 3, 2020

Hi team, we use CosmosSerializer for our migration process. As part of our migration, we deserialize the JSON document from Cosmos as JObject and then update the JObject as per the latest schema of the Document. The advantage of this approach for us is that when using CosmosClient to read a document in our repository the transformation to the latest schema has already happened. Until now, this has worked well for us. However, now we have a requirement where we need to update the JObject from an external resource by doing a network call. If FromStream was async it would have made things much easier for us.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Container.CreateItemAsync<T> Method
Creates a item as an asynchronous operation in the Azure Cosmos service. ... CosmosSerializer to implement a custom serializer.
Read more >
System.Text.Json custom serializer for CosmosDb ...
Text.Json requires extra wotk to handle serialization of class hierarchies. I changed this : SerializeAsync<T>. to this : SerializeAsync<object>.
Read more >
Leveraging Azure Cosmos DB Partial Document Update ...
Utilizing Cosmos DB Partial Updates. The Cosmos DB .NET SDK exposes partial document updates through the PatchItemAsync method on a container.
Read more >
Async Streams with IAsyncEnumerable<T> in .NET Core 3
It exposes an enumerator that has a MoveNextAsync() method that can awaited. This means the producer can make asynchronous calls in between ...
Read more >
Handling type hierarchies in Cosmos DB (part 2)
Let's see how to apply this feature to our problem. First, let add an abstract Type property to the base class of our...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found