Partilhar via


Exportar e importar registos dos Hubs de Notificação do Azure em massa

Há cenários em que é necessário criar ou modificar um grande número de registros em um hub de notificação. Alguns desses cenários incluem atualizações de etiquetas após cálculos em lote ou a migração de uma implementação existente baseada em push para usar os Hubs de Notificação do 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 a granel só está disponível para o nível de preços "padrão"

Fluxo de alto nível

O suporte em lote foi projetado para suportar trabalhos de longa duração que envolvem milhões de registros. Para atingir esta escala, o suporte em batch utiliza o Armazenamento do Azure para armazenar detalhes e resultados do trabalho. Para operações de atualização em massa, o usuário é obrigado a criar um arquivo em um contêiner de blob, cujo conteúdo é a lista de operações de atualização de registro. Ao iniciar o trabalho, o usuário fornece uma URL para o blob de entrada, juntamente com uma URL para um diretório de saída (também em um contêiner de blob). Depois que o trabalho for iniciado, o usuário poderá verificar o status consultando um local de URL fornecido no início do trabalho. Um trabalho específico só pode executar operações de um tipo específico (cria, atualiza ou exclui). As operações de exportação são realizadas de forma análoga.

Importação

Configurar

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

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

Um arquivo de entrada contém uma lista de registros serializados em XML, 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 todo o fluxo em um blob. Se tiveres carregado um ficheiro com mais de apenas alguns megabytes, consulta as orientações de blobs do Azure sobre como realizar estes passos; por exemplo, blobs de bloco.

Criar tokens de URLs

Depois que o arquivo de entrada for carregado, gere as URLs a serem fornecidas ao hub de notificação para o arquivo de entrada e o diretório de saída. 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, agora você pode iniciar o trabalho em lote.

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 NotificationHubJob objeto que contém um JobType objeto, que pode ser um dos seguintes tipos:

  • ImportCreateRegistrations
  • ImportUpdateRegistrations
  • ImportDeleteRegistrations

Quando a chamada for concluída, o trabalho será continuado pelo hub de notificação e você poderá verificar seu status com a chamada para GetNotificationHubJobAsync.

Na conclusão do trabalho, você pode inspecionar os resultados observando os seguintes arquivos no diretório de saída:

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

Esses arquivos contêm a lista de operações bem-sucedidas e com falha do seu lote. O formato do ficheiro é .cvs, em que cada linha tem o número da linha do ficheiro de entrada original e o resultado da operação (geralmente a descrição de registo 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

O registro de exportação é semelhante ao da importação, com as seguintes diferenças:

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

Exemplo de trecho de código

A seguir está um trecho 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óximos passos

Para saber mais sobre registros, consulte os seguintes artigos: