Compartilhar via


Exportar e importar em massa registros dos Hubs de Notificações do Microsoft Azure

Existem cenários em que é necessário criar ou modificar grandes números de registros em um hub de notificação. Alguns desses cenários são atualizações de marcação após computações em lote, ou a migração de uma implementação de push existente para usar Hubs de Notificações do Microsoft Azure.

Este artigo explica como executar um grande número de operações em um hub de notificação ou exportar todos os registros em massa.

OBSERVAÇÃO: A importação/exportação em massa só está disponível para o tipo de preço "padrão"

Fluxo de alto nível

O suporte a operações em lote destina-se a trabalhos de longa duração que envolvem milhões de registros. Para alcançar essa escala, o suporte a operações em lote usa o Armazenamento do Microsoft Azure para armazenar os detalhes e a saída dos trabalhos. Para operações de atualização em massa, o usuário precisa criar um arquivo em um contêiner de blobs, cujo conteúdo é a lista de operações de atualização de registros. Ao iniciar o trabalho, o usuário fornece uma URL para o blob de entrada, junto com uma URL para um diretório de saída (também contido em um contêiner de blobs). Uma vez iniciado o trabalho, o usuário poderá verificar o status consultando um local de URL fornecido no início do trabalho. Um trabalho específico só poderá executar operações de determinado tipo (criações, atualizações ou exclusões). As operações de exportação são executadas de maneira semelhante.

Importar

Configuração

Esta seção pressupõe que você tem as seguintes entidades:

Criar um arquivo de entrada e armazená-lo em um blob

Um arquivo de entrada contém uma lista de registros serializados em XML, sendo um por linha. Usando o SDK do Azure, o exemplo de código a seguir mostra como serializar os registros e carregá-los no contêiner de BLOB:

private static async Task SerializeToBlobAsync(BlobContainerClient container, RegistrationDescription[] descriptions)
{
     StringBuilder builder = new StringBuilder();
     foreach (var registrationDescription in descriptions)
     {
          builder.AppendLine(registrationDescription.Serialize());
     }

     var inputBlob = container.GetBlobClient(INPUT_FILE_NAME);
     using (MemoryStream stream = new MemoryStream(Encoding.UTF8.GetBytes(builder.ToString())))
     {
         await inputBlob.UploadAsync(stream);
     }
}

Importante

O código anterior serializa os registros na memória e, em seguida, carrega o fluxo inteiro em um blob. Se você tiver carregado um arquivo de mais de alguns megabytes, consulte a orientação de BLOB do Azure para saber como executar essas etapas; por exemplo, blobs de blocos.

Criar tokens de URL

Uma vez carregado o arquivo de entrada, gere as URLs para o arquivo de entrada e o diretório de saída a fim de fornecê-las ao hub de notificação. Você pode usar dois contêineres de BLOB diferentes para entrada e saída.

static Uri GetOutputDirectoryUrl(BlobContainerClient container)
{
      Console.WriteLine(container.CanGenerateSasUri);
      BlobSasBuilder builder = new BlobSasBuilder(BlobSasPermissions.All, DateTime.UtcNow.AddDays(1));
      return container.GenerateSasUri(builder);
}

static Uri GetInputFileUrl(BlobContainerClient container, string filePath)
{
      Console.WriteLine(container.CanGenerateSasUri);
      BlobSasBuilder builder = new BlobSasBuilder(BlobSasPermissions.Read, DateTime.UtcNow.AddDays(1));
      return container.GenerateSasUri(builder);
}

Enviar o trabalho

Com as duas URLs de entrada e saída, você poderá iniciar o trabalho em lotes.

NotificationHubClient client = NotificationHubClient.CreateClientFromConnectionString(CONNECTION_STRING, HUB_NAME);
var job = await client.SubmitNotificationHubJobAsync(
     new NotificationHubJob {
             JobType = NotificationHubJobType.ImportCreateRegistrations,
             OutputContainerUri = outputContainerSasUri,
             ImportFileUri = inputFileSasUri
         }
     );

long i = 10;
while (i > 0 && job.Status != NotificationHubJobStatus.Completed)
{
    job = await client.GetNotificationHubJobAsync(job.JobId);
    await Task.Delay(1000);
    i--;
}

Além das URLs de entrada e saída, este exemplo cria um objeto NotificationHubJob que contém um objeto JobType, que poderá ser um dos seguintes tipos:

  • ImportCreateRegistrations
  • ImportUpdateRegistrations
  • ImportDeleteRegistrations

Quando a chamada for concluída, o hub de notificação dará continuidade ao trabalho, e você poderá verificar o seu status com a chamada de GetNotificationHubJobAsync.

Quando o trabalho for concluído, você poderá verificar os resultados examinando os seguintes arquivos em seu diretório de saída:

  • /<hub>/<jobid>/Failed.txt
  • /<hub>/<jobid>/Output.txt

Esses arquivos contêm a lista das operações de seu lote que foram bem-sucedidas e falharam. O formato do arquivo é .cvs, no qual cada linha contém o número da linha do arquivo de entrada original e a saída da operação (geralmente a descrição de registro criada ou atualizada).

Código de exemplo completo

O código de exemplo a seguir importa registros para um hub de notificação.

using Microsoft.Azure.NotificationHubs;
using Azure.Storage.Blobs;
using Azure.Storage.Sas;
using System.Text;

namespace ConsoleApplication1
{
    class Program
    {
        private static string CONNECTION_STRING = "namespace"; 
        private static string HUB_NAME = "demohub";
        private static string INPUT_FILE_NAME = "CreateFile.txt";
        private static string STORAGE_ACCOUNT_CONNECTIONSTRING = "connectionstring";
        private static string CONTAINER_NAME = "containername";

        static async Task Main(string[] args)
        {
            var descriptions = new[]
            {
                new MpnsRegistrationDescription(@"http://dm2.notify.live.net/throttledthirdparty/01.00/12G9Ed13dLb5RbCii5fWzpFpAgAAAAADAQAAAAQUZm52OkJCMjg1QTg1QkZDMkUxREQFBlVTTkMwMQ"),
                new MpnsRegistrationDescription(@"http://dm2.notify.live.net/throttledthirdparty/01.00/12G9Ed13dLb5RbCii5fWzpFpAgAAAAADAQAAAAQUZm52OkJCMjg1QTg1QkZDMjUxREQFBlVTTkMwMQ"),
                new MpnsRegistrationDescription(@"http://dm2.notify.live.net/throttledthirdparty/01.00/12G9Ed13dLb5RbCii5fWzpFpAgAAAAADAQAAAAQUZm52OkJCMjg1QTg1QkZDMhUxREQFBlVTTkMwMQ"),
                new MpnsRegistrationDescription(@"http://dm2.notify.live.net/throttledthirdparty/01.00/12G9Ed13dLb5RbCii5fWzpFpAgAAAAADAQAAAAQUZm52OkJCMjg1QTg1QkZDMdUxREQFBlVTTkMwMQ"),
            };

            // Get a reference to a container named "sample-container" and then create it
            BlobContainerClient container = new BlobContainerClient(STORAGE_ACCOUNT_CONNECTIONSTRING, CONTAINER_NAME);

            await container.CreateIfNotExistsAsync();

            await SerializeToBlobAsync(container, descriptions);

            // TODO then create Sas
            var outputContainerSasUri = GetOutputDirectoryUrl(container);
            
            BlobContainerClient inputcontainer = new BlobContainerClient(STORAGE_ACCOUNT_CONNECTIONSTRING, STORAGE_ACCOUNT_CONNECTIONSTRING + "/" +         INPUT_FILE_NAME);

            var inputFileSasUri = GetInputFileUrl(inputcontainer, INPUT_FILE_NAME);


            // Import this file
            NotificationHubClient client = NotificationHubClient.CreateClientFromConnectionString(CONNECTION_STRING, HUB_NAME);
            var job = await client.SubmitNotificationHubJobAsync(
                new NotificationHubJob {
                    JobType = NotificationHubJobType.ImportCreateRegistrations,
                    OutputContainerUri = outputContainerSasUri,
                    ImportFileUri = inputFileSasUri
                }
            );

            long i = 10;
            while (i > 0 && job.Status != NotificationHubJobStatus.Completed)
            {
                job = await client.GetNotificationHubJobAsync(job.JobId);
                await Task.Delay(1000);
                i--;
            }
        }

        private static async Task SerializeToBlobAsync(BlobContainerClient container, RegistrationDescription[] descriptions)
        {
            StringBuilder builder = new StringBuilder();
            foreach (var registrationDescription in descriptions)
            {
                builder.AppendLine(registrationDescription.Serialize());
            }

            var inputBlob = container.GetBlobClient(INPUT_FILE_NAME);
            using (MemoryStream stream = new MemoryStream(Encoding.UTF8.GetBytes(builder.ToString())))
            {
                await inputBlob.UploadAsync(stream);
            }
        }

        static Uri GetOutputDirectoryUrl(BlobContainerClient container)
        {
            Console.WriteLine(container.CanGenerateSasUri);
            BlobSasBuilder builder = new BlobSasBuilder(BlobSasPermissions.All, DateTime.UtcNow.AddDays(1));
            return container.GenerateSasUri(builder);
        }

        static Uri GetInputFileUrl(BlobContainerClient container, string filePath)
        {
            Console.WriteLine(container.CanGenerateSasUri);
            BlobSasBuilder builder = new BlobSasBuilder(BlobSasPermissions.Read, DateTime.UtcNow.AddDays(1));
            return container.GenerateSasUri(builder);

        }
    }
}

Exportação

A exportação do registro é semelhante à importação, com as seguintes diferenças:

  • Você precisa somente da URL de saída.
  • Você cria um NotificationHubJob do tipo ExportRegistrations.

Snippet de código de exemplo

Veja a seguir um snippet de código de exemplo para exportar registros em Java:

// Submit an export job
NotificationHubJob job = new NotificationHubJob();
job.setJobType(NotificationHubJobType.ExportRegistrations);
job.setOutputContainerUri("container uri with SAS signature");
job = hub.submitNotificationHubJob(job);

// Wait until the job is done
while(true){
    Thread.sleep(1000);
    job = hub.getNotificationHubJob(job.getJobId());
    if(job.getJobStatus() == NotificationHubJobStatus.Completed)
        break;
}

Próximas etapas

Para saber mais sobre registros, consulte os seguintes artigos: