Migrar a aplicação para utilizar o SDK .NET v3 do Azure Cosmos DB

APLICA-SE A: NoSQL

Importante

Para saber mais sobre o SDK .NET v3 do Azure Cosmos DB, veja as Notas de versão, o repositório do GitHub .NET, as Sugestões de Desempenho do SDK .NET v3 e o Guia de resolução de problemas.

Este artigo destaca algumas das considerações de atualização da sua aplicação .NET existente para o SDK .NET v3 do Azure Cosmos DB mais recente para a API para NoSQL. O SDK .NET v3 do Azure Cosmos DB corresponde ao espaço de nomes Microsoft.Azure.Azure Cosmos DB. Pode utilizar as informações fornecidas neste documento se estiver a migrar a sua aplicação a partir de qualquer um dos seguintes SDKs .NET do Azure Cosmos DB:

  • Azure Cosmos DB .NET Framework SDK v2 para API para NoSQL
  • SDK .NET Core v2 do Azure Cosmos DB para API para NoSQL

As instruções neste artigo também o ajudam a migrar as seguintes bibliotecas externas que agora fazem parte do SDK .NET v3 do Azure Cosmos DB para API para NoSQL:

  • Biblioteca 2.0 do processador do feed de alterações .NET
  • Biblioteca de executor em massa .NET 1.1 ou superior

Novidades no SDK .NET V3

O SDK v3 contém muitos melhoramentos de desempenho e utilização, incluindo:

  • Nomenclatura de modelos de programação intuitiva
  • .NET Standard 2.0 **
  • Aumento do desempenho através do suporte da API de fluxo
  • Hierarquia Fluent que substitui a necessidade de fábrica de URI
  • Suporte incorporado para a biblioteca do processador do feed de alterações
  • Suporte incorporado para operações em massa
  • APIs mockable para testes de unidades mais fáceis
  • Suporte transacional do Batch e do Blazor
  • Serializadores pluggable
  • Dimensionar contentores não particionados e dimensionar automaticamente

** O SDK destina-se ao .NET Standard 2.0 que unifica os SDKs do Azure Cosmos DB .NET Framework e .NET Core existentes num único SDK .NET. Pode utilizar o SDK .NET em qualquer plataforma que implemente o .NET Standard 2.0, incluindo as aplicações .NET Framework 4.6.1+ e .NET Core 2.0 e posterior.

A maioria das redes, lógica de repetição e níveis inferiores do SDK permanecem praticamente inalterados.

O SDK .NET v3 do Azure Cosmos DB está agora open source. Congratulamo-nos com quaisquer pedidos Pull e iremos registar problemas e controlar o feedback no GitHub. Vamos trabalhar para assumir todas as funcionalidades que irão melhorar a experiência do cliente.

Porquê migrar para o SDK .NET v3

Além das inúmeras melhorias de utilização e desempenho, os novos investimentos de funcionalidades efetuados no SDK mais recente não voltarão a ser migrados para versões mais antigas. O SDK v2 está atualmente no modo de manutenção. Para obter a melhor experiência de desenvolvimento, recomendamos que comece sempre com a versão suportada mais recente do SDK.

O nome principal muda do SDK v2 para o SDK v3

As seguintes alterações de nome foram aplicadas em todo o SDK .NET 3.0 para alinhar com as convenções de nomenclatura de API para a API para NoSQL:

  • DocumentClient o nome foi mudado para CosmosClient
  • Collection o nome foi mudado para Container
  • Document o nome foi mudado para Item

Todos os objetos de recursos são renomeados com propriedades adicionais, que incluem o nome do recurso para maior clareza.

Seguem-se algumas das principais alterações ao nome da classe:

SDK .NET v2 SDK .NET v3
Microsoft.Azure.Documents.Client.DocumentClient Microsoft.Azure.Cosmos.CosmosClient
Microsoft.Azure.Documents.Client.ConnectionPolicy Microsoft.Azure.Cosmos.CosmosClientOptions
Microsoft.Azure.Documents.Client.DocumentClientException Microsoft.Azure.Cosmos.CosmosException
Microsoft.Azure.Documents.Client.Database Microsoft.Azure.Cosmos.DatabaseProperties
Microsoft.Azure.Documents.Client.DocumentCollection Microsoft.Azure.Cosmos.ContainerProperties
Microsoft.Azure.Documents.Client.RequestOptions Microsoft.Azure.Cosmos.ItemRequestOptions
Microsoft.Azure.Documents.Client.FeedOptions Microsoft.Azure.Cosmos.QueryRequestOptions
Microsoft.Azure.Documents.Client.StoredProcedure Microsoft.Azure.Cosmos.StoredProcedureProperties
Microsoft.Azure.Documents.Client.Trigger Microsoft.Azure.Cosmos.TriggerProperties
Microsoft.Azure.Documents.SqlQuerySpec Microsoft.Azure.Cosmos.QueryDefinition

Classes substituídas no SDK .NET v3

As seguintes classes foram substituídas no SDK 3.0:

  • Microsoft.Azure.Documents.UriFactory

A classe Microsoft.Azure.Documents.UriFactory foi substituída pelo design fluente.

Container container = client.GetContainer(databaseName,containerName);
ItemResponse<SalesOrder> response = await this._container.CreateItemAsync(
        salesOrder,
        new PartitionKey(salesOrder.AccountNumber));

  • Microsoft.Azure.Documents.Document

Uma vez que o SDK .NET v3 permite aos utilizadores configurar um motor de serialização personalizado, não existe substituição direta do Document tipo. Ao utilizar Newtonsoft.Json (motor de serialização predefinido), JObject pode ser utilizado para obter a mesma funcionalidade. Ao utilizar um motor de serialização diferente, pode utilizar o tipo de documento json base (por exemplo, JsonDocument para System.Text.Json). A recomendação é utilizar um tipo de C# que reflita o esquema dos seus itens em vez de depender de tipos genéricos.

  • Microsoft.Azure.Documents.Resource

Não existe substituição direta para Resource, nos casos em que foi utilizado para documentos, siga as orientações para Document.

  • Microsoft.Azure.Documents.AccessCondition

IfNoneMatch ou IfMatch estão agora disponíveis diretamente no Microsoft.Azure.Cosmos.ItemRequestOptions .

Alterações à geração de ID de item

O ID do Item já não é preenchido automaticamente no SDK .NET v3. Por conseguinte, o ID do Item tem de incluir especificamente um ID gerado. Veja o seguinte exemplo:

[JsonProperty(PropertyName = "id")]
public Guid Id { get; set; }

Comportamento predefinido alterado para o modo de ligação

Agora, o SDK v3 é predefinido para os modos de ligação Direct + TCP em comparação com o SDK v2 anterior, que predefiniu os modos de ligação Gateway + HTTPS. Esta alteração proporciona um melhor desempenho e escalabilidade.

Alterações ao FeedOptions (QueryRequestOptions no SDK v3.0)

A FeedOptions classe no SDK v2 foi agora renomeada para QueryRequestOptions no SDK v3 e, dentro da classe, várias propriedades tiveram alterações no nome e/ou no valor predefinido ou foram removidas completamente.

SDK .NET v2 SDK .NET v3
FeedOptions.MaxDegreeOfParallelism QueryRequestOptions.MaxConcurrency - O valor predefinido e o comportamento associado permanecem os mesmos. As operações executam o lado do cliente durante a execução paralela da consulta serão executadas em série sem paralelismo.
FeedOptions.PartitionKey QueryRequestOptions.PartitionKey - Comportamento mantido.
FeedOptions.EnableCrossPartitionQuery Removidos. O comportamento predefinido no SDK 3.0 é que as consultas entre partições serão executadas sem a necessidade de ativar a propriedade especificamente.
FeedOptions.PopulateQueryMetrics Removidos. Está agora ativada por predefinição e faz parte dos diagnósticos.
FeedOptions.RequestContinuation Removidos. É agora promovido para os próprios métodos de consulta.
FeedOptions.JsonSerializerSettings Removidos. Veja como personalizar a serialização para obter informações adicionais.
FeedOptions.PartitionKeyRangeId Removidos. O mesmo resultado pode ser obtido através da utilização de FeedRange como entrada para o método de consulta.
FeedOptions.DisableRUPerMinuteUsage Removidos.

Construir um cliente

O SDK .NET v3 fornece uma classe fluente CosmosClientBuilder que substitui a necessidade do SDK v2 URI Factory.

O design fluente cria URLs internamente e permite que um único Container objeto seja transmitido em vez de um DocumentClient, DatabaseNamee DocumentCollection.

O exemplo seguinte cria um novo CosmosClientBuilder com um ConsistencyLevel forte e uma lista de localizações preferenciais:

CosmosClientBuilder cosmosClientBuilder = new CosmosClientBuilder(
    accountEndpoint: "https://testcosmos.documents.azure.com:443/",
    authKeyOrResourceToken: "SuperSecretKey")
.WithConsistencyLevel(ConsistencyLevel.Strong)
.WithApplicationRegion(Regions.EastUS);
CosmosClient client = cosmosClientBuilder.Build();

Exceções

Quando o SDK v2 utilizado DocumentClientException para sinalizar erros durante as operações, o SDK v3 utiliza CosmosException, o que expõe as StatusCodeinformações relacionadas com , Diagnosticse outras informações relacionadas com a resposta. Todas as informações completas são serializadas quando ToString() são utilizadas:

catch (CosmosException ex)
{
    HttpStatusCode statusCode = ex.StatusCode;
    CosmosDiagnostics diagnostics = ex.Diagnostics;
    // store diagnostics optionally with diagnostics.ToString();
    // or log the entire error details with ex.ToString();
}

Diagnóstico

Quando o SDK v2 tinha diagnósticos apenas diretos disponíveis através da RequestDiagnosticsString propriedade, o SDK v3 utiliza Diagnostics disponível em todas as respostas e exceções, que são mais ricas e não restritas ao modo Direto. Incluem não só o tempo gasto no SDK para a operação, mas também as regiões que a operação contactou:

try
{
    ItemResponse<MyItem> response = await container.ReadItemAsync<MyItem>(
                    partitionKey: new PartitionKey("MyPartitionKey"),
                    id: "MyId");
    
    TimeSpan elapsedTime = response.Diagnostics.GetElapsedTime();
    if (elapsedTime > somePreDefinedThreshold)
    {
        // log response.Diagnostics.ToString();
        IReadOnlyList<(string region, Uri uri)> regions = response.Diagnostics.GetContactedRegions();
    }
}
catch (CosmosException cosmosException) {
    string diagnostics = cosmosException.Diagnostics.ToString();
    
    TimeSpan elapsedTime = cosmosException.Diagnostics.GetElapsedTime();
    
    IReadOnlyList<(string region, Uri uri)> regions = cosmosException.Diagnostics.GetContactedRegions();
    
    // log cosmosException.ToString()
}

ConnectionPolicy

Algumas definições no ConnectionPolicy foram renomeadas ou substituídas por CosmosClientOptions:

SDK .NET v2 SDK .NET v3
EnableEndpointRediscovery LimitToEndpoint - O valor está agora invertido, se EnableEndpointRediscovery estava a ser definido como true, LimitToEndpoint deve ser definido como false. Antes de utilizar esta definição, tem de compreender como afeta o cliente.
ConnectionProtocol Removidos. O protocolo está associado ao Modo, ou é Gateway (HTTPS) ou Direto (TCP). O modo direto com o protocolo HTTPS já não é suportado no SDK V3 e a recomendação é utilizar o protocolo TCP.
MediaRequestTimeout Removidos. Os anexos já não são suportados.
SetCurrentLocation CosmosClientOptions.ApplicationRegion pode ser utilizado para obter o mesmo efeito.
PreferredLocations CosmosClientOptions.ApplicationPreferredRegions pode ser utilizado para obter o mesmo efeito.
UserAgentSuffix CosmosClientBuilder.ApplicationName pode ser utilizado para obter o mesmo efeito.
UseMultipleWriteLocations Removidos. O SDK deteta automaticamente se a conta suporta vários pontos finais de escrita.

Política de indexação

Na política de indexação, não é possível configurar estas propriedades. Quando não forem especificadas, estas propriedades terão agora sempre os seguintes valores:

Nome da Propriedade Novo Valor (não configurável)
Kind range
dataType String e Number

Veja esta secção para obter exemplos de políticas de indexação para incluir e excluir caminhos. Devido a melhorias no motor de consulta, a configuração destas propriedades, mesmo que utilize uma versão mais antiga do SDK, não tem qualquer impacto no desempenho.

Token de sessão

Quando o SDK v2 expôs o token de sessão de uma resposta como ResourceResponse.SessionToken nos casos em que era necessário capturar o token de sessão, uma vez que o token de sessão é um cabeçalho, o SDK v3 expõe esse valor na Headers.Session propriedade de qualquer resposta.

CarimboDeDataEHora

Quando o SDK v2 expôs o carimbo de data/hora de um documento através da Timestamp propriedade, uma vez Document que já não está disponível, os utilizadores podem mapear a propriedade do _ts sistema para uma propriedade no respetivo modelo.

OpenAsync

Para casos de utilização em OpenAsync() que estava a ser utilizado para aquecer o cliente do SDK v2, CreateAndInitializeAsync pode ser utilizado para criar e aquecer um cliente SDK v3.

Utilizar as APIs do processador do feed de alterações diretamente a partir do SDK v3

O SDK v3 tem suporte incorporado para as APIs do Processador do Feed de Alterações, o que lhe permite utilizar o mesmo SDK para criar a aplicação e a implementação do processador do feed de alterações. Anteriormente, tinha de utilizar uma biblioteca separada do processador do feed de alterações.

Para obter mais informações, veja como migrar da biblioteca do processador do feed de alterações para o SDK .NET v3 do Azure Cosmos DB

Consultas do feed de alterações

A execução de consultas do feed de alterações no SDK v3 é considerada como estando a utilizar o modelo de solicitação do feed de alterações. Siga esta tabela para migrar a configuração:

SDK .NET v2 SDK .NET v3
ChangeFeedOptions.PartitionKeyRangeId FeedRange - Para alcançar o paralelismo, pode ser utilizada a leitura do feed de alterações FeedRanges . Já não é um parâmetro necessário. Agora pode ler facilmente o Feed de Alterações de um contentor inteiro .
ChangeFeedOptions.PartitionKey FeedRange.FromPartitionKey - Um FeedRange que representa a Chave de Partição pretendida pode ser utilizado para ler o Feed de Alterações desse valor da Chave de Partição.
ChangeFeedOptions.RequestContinuation ChangeFeedStartFrom.Continuation - O iterador do feed de alterações pode ser parado e retomado em qualquer altura ao guardar a continuação e utilizá-la ao criar um novo iterador.
ChangeFeedOptions.StartTime ChangeFeedStartFrom.Time
ChangeFeedOptions.StartFromBeginning ChangeFeedStartFrom.Beginning
ChangeFeedOptions.MaxItemCount ChangeFeedRequestOptions.PageSizeHint - O iterador do feed de alterações pode ser parado e retomado em qualquer altura ao guardar a continuação e utilizá-la ao criar um novo iterador.
IDocumentQuery.HasMoreResults response.StatusCode == HttpStatusCode.NotModified - O feed de alterações é conceptualmente infinito, pelo que pode haver sempre mais resultados. Quando uma resposta contém o HttpStatusCode.NotModified código de estado, significa que não existem novas alterações para ler neste momento. Pode utilizá-lo para parar e guardar a continuação ou para suspender temporariamente ou esperar e, em seguida, ligar ReadNextAsync novamente para testar novas alterações.
Processamento de divisões Já não é necessário que os utilizadores processem exceções divididas ao ler o feed de alterações, as divisões serão processadas de forma transparente sem a necessidade de interação do utilizador.

Utilizar a biblioteca do executor em massa diretamente a partir do SDK V3

O SDK v3 tem suporte incorporado para a biblioteca do executor em massa, permitindo-lhe utilizar o mesmo SDK para criar a sua aplicação e realizar operações em massa. Anteriormente, era necessário utilizar uma biblioteca de executor em massa separada.

Para obter mais informações, veja como migrar da biblioteca do executor em massa para o suporte em massa no SDK .NET V3 do Azure Cosmos DB

Personalizar a serialização

O SDK .NET V2 permite definir JsonSerializerSettings em RequestOptions ao nível operacional utilizado para anular a serialização do documento de resultados:

// .NET V2 SDK
var result = await container.ReplaceDocumentAsync(document, new RequestOptions { JsonSerializerSettings = customSerializerSettings })

O SDK .NET v3 fornece uma interface de serializador para personalizar totalmente o motor de serialização ou opções de serialização mais genéricas como parte da construção do cliente.

A personalização da serialização ao nível da operação pode ser obtida através da utilização de APIs do Stream:

// .NET V3 SDK
using(Response response = await this.container.ReplaceItemStreamAsync(stream, "itemId", new PartitionKey("itemPartitionKey"))
{

    using(Stream stream = response.ContentStream)
    {
        using (StreamReader streamReader = new StreamReader(stream))
        {
            // Read the stream and do dynamic deserialization based on type with a custom Serializer
        }
    }
}

Comparações de fragmentos de código

O fragmento de código seguinte mostra as diferenças na forma como os recursos são criados entre os SDKs .NET v2 e v3:

Operações da base de dados

Criar uma base de dados

// Create database with no shared provisioned throughput
DatabaseResponse databaseResponse = await client.CreateDatabaseIfNotExistsAsync(DatabaseName);
Database database = databaseResponse;
DatabaseProperties databaseProperties = databaseResponse;

// Create a database with a shared manual provisioned throughput
string databaseIdManual = new string(DatabaseName + "_SharedManualThroughput");
database = await client.CreateDatabaseIfNotExistsAsync(databaseIdManual, ThroughputProperties.CreateManualThroughput(400));

// Create a database with shared autoscale provisioned throughput
string databaseIdAutoscale = new string(DatabaseName + "_SharedAutoscaleThroughput");
database = await client.CreateDatabaseIfNotExistsAsync(databaseIdAutoscale, ThroughputProperties.CreateAutoscaleThroughput(4000));

Ler uma base de dados por ID

// Read a database
Console.WriteLine($"{Environment.NewLine} Read database resource: {DatabaseName}");
database = client.GetDatabase(DatabaseName);
Console.WriteLine($"{Environment.NewLine} database { database.Id.ToString()}");

// Read all databases
string findQueryText = "SELECT * FROM c";
using (FeedIterator<DatabaseProperties> feedIterator = client.GetDatabaseQueryIterator<DatabaseProperties>(findQueryText))
{
    while (feedIterator.HasMoreResults)
    {
        FeedResponse<DatabaseProperties> databaseResponses = await feedIterator.ReadNextAsync();
        foreach (DatabaseProperties _database in databaseResponses)
        {
            Console.WriteLine($"{ Environment.NewLine} database {_database.Id.ToString()}");
        }
    }
}

Eliminar uma base de dados

// Delete a database
await client.GetDatabase(DatabaseName).DeleteAsync();
Console.WriteLine($"{ Environment.NewLine} database {DatabaseName} deleted.");

// Delete all databases in an account
string deleteQueryText = "SELECT * FROM c";
using (FeedIterator<DatabaseProperties> feedIterator = client.GetDatabaseQueryIterator<DatabaseProperties>(deleteQueryText))
{
    while (feedIterator.HasMoreResults)
    {
        FeedResponse<DatabaseProperties> databaseResponses = await feedIterator.ReadNextAsync();
        foreach (DatabaseProperties _database in databaseResponses)
        {
            await client.GetDatabase(_database.Id).DeleteAsync();
            Console.WriteLine($"{ Environment.NewLine} database {_database.Id} deleted");
        }
    }
}

Operações de contentor

Criar um contentor (Dimensionamento Automático + Tempo de vida com expiração)

private static async Task CreateManualThroughputContainer(Database database)
{
    // Set throughput to the minimum value of 400 RU/s manually configured throughput
    string containerIdManual = ContainerName + "_Manual";
    ContainerResponse container = await database.CreateContainerIfNotExistsAsync(
        id: containerIdManual,
        partitionKeyPath: partitionKeyPath,
        throughput: 400);
}

// Create container with autoscale
private static async Task CreateAutoscaleThroughputContainer(Database database)
{
    string autoscaleContainerId = ContainerName + "_Autoscale";
    ContainerProperties containerProperties = new ContainerProperties(autoscaleContainerId, partitionKeyPath);

    Container container = await database.CreateContainerIfNotExistsAsync(
        containerProperties: containerProperties,
        throughputProperties: ThroughputProperties.CreateAutoscaleThroughput(autoscaleMaxThroughput: 4000);
}

// Create a container with TTL Expiration
private static async Task CreateContainerWithTtlExpiration(Database database)
{
    string containerIdManualwithTTL = ContainerName + "_ManualTTL";

    ContainerProperties properties = new ContainerProperties
        (id: containerIdManualwithTTL,
        partitionKeyPath: partitionKeyPath);

    properties.DefaultTimeToLive = (int)TimeSpan.FromDays(1).TotalSeconds; //expire in 1 day

    ContainerResponse containerResponse = await database.CreateContainerIfNotExistsAsync(containerProperties: properties);
    ContainerProperties returnedProperties = containerResponse;
}

Ler as propriedades do contentor

private static async Task ReadContainerProperties(Database database)
{
    string containerIdManual = ContainerName + "_Manual";
    Container container = database.GetContainer(containerIdManual);
    ContainerProperties containerProperties = await container.ReadContainerAsync();
}

Eliminar um contentor

private static async Task DeleteContainers(Database database)
{
    string containerIdManual = ContainerName + "_Manual";

    // Delete a container
    await database.GetContainer(containerIdManual).DeleteContainerAsync();

    // Delete all CosmosContainer resources for a database
    using (FeedIterator<ContainerProperties> feedIterator = database.GetContainerQueryIterator<ContainerProperties>())
    {
        while (feedIterator.HasMoreResults)
        {
            foreach (ContainerProperties _container in await feedIterator.ReadNextAsync())
            {
                await database.GetContainer(_container.Id).DeleteContainerAsync();
                Console.WriteLine($"{Environment.NewLine}  deleted container {_container.Id}");
            }
        }
    }
}

Operações de item e consulta

Criar um item

private static async Task CreateItemAsync(Container container)
{
    // Create a SalesOrder POCO object
    SalesOrder salesOrder1 = GetSalesOrderSample("Account1", "SalesOrder1");
    ItemResponse<SalesOrder> response = await container.CreateItemAsync(salesOrder1,
        new PartitionKey(salesOrder1.AccountNumber));
}

private static async Task RunBasicOperationsOnDynamicObjects(Container container)
{
    // Dynamic Object
    dynamic salesOrder = new
    {
        id = "SalesOrder5",
        AccountNumber = "Account1",
        PurchaseOrderNumber = "PO18009186470",
        OrderDate = DateTime.UtcNow,
        Total = 5.95,
    };
    Console.WriteLine("\nCreating item");
    ItemResponse<dynamic> response = await container.CreateItemAsync<dynamic>(
        salesOrder, new PartitionKey(salesOrder.AccountNumber));
    dynamic createdSalesOrder = response.Resource;
}

Ler todos os itens num contentor

private static async Task ReadAllItems(Container container)
{
    // Read all items in a container
    List<SalesOrder> allSalesForAccount1 = new List<SalesOrder>();

    using (FeedIterator<SalesOrder> resultSet = container.GetItemQueryIterator<SalesOrder>(
        queryDefinition: null,
        requestOptions: new QueryRequestOptions()
        {
            PartitionKey = new PartitionKey("Account1"),
            MaxItemCount = 5
        }))
    {
        while (resultSet.HasMoreResults)
        {
            FeedResponse<SalesOrder> response = await resultSet.ReadNextAsync();
            SalesOrder salesOrder = response.First();
            Console.WriteLine($"\n1.3.1 Account Number: {salesOrder.AccountNumber}; Id: {salesOrder.Id}");
            allSalesForAccount1.AddRange(response);
        }
    }
}

Consultar itens

Alterações ao SqlQuerySpec (QueryDefinition no SDK v3.0)

A SqlQuerySpec classe no SDK v2 foi agora renomeada para QueryDefinition no SDK v3.

SqlParameterCollection e SqlParameter foi removido. Os parâmetros são agora adicionados ao QueryDefinition com um modelo de construtor com QueryDefinition.WithParameter. Os utilizadores podem aceder aos parâmetros com QueryDefinition.GetQueryParameters

private static async Task QueryItems(Container container)
{
    // Query for items by a property other than Id
    QueryDefinition queryDefinition = new QueryDefinition(
        "select * from sales s where s.AccountNumber = @AccountInput")
        .WithParameter("@AccountInput", "Account1");

    List<SalesOrder> allSalesForAccount1 = new List<SalesOrder>();
    using (FeedIterator<SalesOrder> resultSet = container.GetItemQueryIterator<SalesOrder>(
        queryDefinition,
        requestOptions: new QueryRequestOptions()
        {
            PartitionKey = new PartitionKey("Account1"),
            MaxItemCount = 1
        }))
    {
        while (resultSet.HasMoreResults)
        {
            FeedResponse<SalesOrder> response = await resultSet.ReadNextAsync();
            SalesOrder sale = response.First();
            Console.WriteLine($"\n Account Number: {sale.AccountNumber}; Id: {sale.Id};");
            allSalesForAccount1.AddRange(response);
        }
    }
}

Eliminar um item

private static async Task DeleteItemAsync(Container container)
{
    ItemResponse<SalesOrder> response = await container.DeleteItemAsync<SalesOrder>(
        partitionKey: new PartitionKey("Account1"), id: "SalesOrder3");
}

Consulta do feed de alterações

private static async Task QueryChangeFeedAsync(Container container)
{
    FeedIterator<SalesOrder> iterator = container.GetChangeFeedIterator<SalesOrder>(ChangeFeedStartFrom.Beginning(), ChangeFeedMode.Incremental);

    string continuation = null;
    while (iterator.HasMoreResults)
    {
        FeedResponse<SalesOrder> response = await iteratorForTheEntireContainer.ReadNextAsync();
    
        if (response.StatusCode == HttpStatusCode.NotModified)
        {
            // No new changes
            continuation = response.ContinuationToken;
            break;
        }
        else 
        {
            // Process the documents in response
        }
    }
}

Passos seguintes