Massenexportieren und -importieren von Azure Notification Hubs-Registrierungen

In einigen Szenarios ist das Erstellen oder Anpassen großer Mengen von Registrierungen in einem Notification Hub erforderlich. Bei einigen dieser Szenarios handelt es sich um Tagaktualisierungen, die auf Batchberechnungen folgen, oder Migrationen vorhandener Pushimplementierungen zur Verwendung von Azure Notification Hubs.

In diesem Artikel wird erläutert, wie Sie große Mengen von Vorgängen in einem Notification Hub durchführen oder alle Registrierungen in einem Massenvorgang exportieren.

HINWEIS: Massenimport/-export ist nur für den Tarif „Standard“ verfügbar.

Allgemeiner Ablauf

Die Batchunterstützung wurde dazu entworfen, Aufträge mit langer Ausführungszeit mit Millionen von Registrierungen zu unterstützen. Die Batchunterstützung nutzt Azure Storage zum Speichern von Auftragsdetails und Ausgaben, um diese Skalierung zu ermöglichen. Für Massenaktualisierungsvorgänge muss der Benutzer eine Datei in einem Blobcontainer erstellen, die eine Liste der Registrierungaktualisierungsvorgänge enthält. Wenn der Auftrag gestartet wird, stellt der Benutzer die jeweiligen URLs zu den Blobcontainern für das Eingabe- und das Ausgabeverzeichnis bereit. Nachdem der Auftrag gestartet wurde, kann der Benutzer den Status überprüfen, indem er einen URL-Speicherort abfragt, der beim Starten des Auftrags bereitgestellt wird. Ein spezifischer Auftrag kann nur Vorgänge einer spezifischen Art (Erstellen, Aktualisieren oder Löschen) durchführen. Exportvorgänge werden analog durchgeführt.

Importieren

Einrichten

In diesem Abschnitt wird vorausgesetzt, dass Sie über folgende Entitäten verfügen:

Erstellen einer Eingabedatei und Speichern in einem Blob

Eine Eingabedatei enthält eine Liste von Registrierungen, die pro Zeile in XML serialisiert sind. Im folgenden Beispiel wird mithilfe des Azure SDK veranschaulicht, wie die Registrierungen serialisiert und in den Blobcontainer hochgeladen werden:

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);
     }
}

Wichtig

Im obigen Code werden die Registrierungen im Arbeitsspeicher serialisiert, und der gesamte Datenstrom wird dann in einen Blob hochgeladen. Wenn Sie eine Datei mit mehreren Megabytes hochgeladen haben, finden Sie Informationen zum Ausführen dieser Schritte in den Anleitungen zu Azure-Blobs, z. B. unter Understanding Block Blobs, Append Blobs, and Page Blobs (Grundlegendes zu Blockblobs, Anfügeblobs und Seitenblobs).

Erstellen von URL-Token

Sobald Sie Ihre Eingabedatei hochgeladen haben, generieren Sie die URLs für die Eingabedatei und das Ausgabeverzeichnis, die Ihrem Notification Hub bereitgestellt werden sollen. Sie können zwei verschiedene Blobcontainer für die Eingabe und die Ausgabe verwenden.

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);
}

Übermitteln des Auftrags

Mit den zwei Eingabe- und Ausgabe-URLs können Sie nun den Batchauftrag starten.

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--;
}

Neben den Eingabe- und Ausgabe-URLs wird in diesem Beispiel ein NotificationHubJob-Objekt erstellt, das ein JobType-Objekt enthält, das einen der folgenden Typen aufweisen kann:

  • ImportCreateRegistrations
  • ImportUpdateRegistrations
  • ImportDeleteRegistrations

Sobald der Aufruf abgeschlossen ist, wird der Auftrag von Notification Hub fortgesetzt, und Sie können seinen Status überprüfen, indem Sie GetNotificationHubJobAsync aufrufen.

Bei Abschluss des Auftrags können Sie die Ergebnisse untersuchen, indem Sie sich die folgenden Dateien in Ihrem Ausgabeverzeichnis ansehen:

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

Diese Dateien enthalten die Liste der erfolgreichen und fehlgeschlagenen Vorgänge im Batch. Die Dateien weisen das Format .cvs auf, in den Dateien weist jede Zeile die Zeilennummer der ursprünglichen Eingabedatei und die Ausgabe des Vorgangs auf (normalerweise die erstellte oder aktualisierte Beschreibung der Registrierung).

Vollständiger Beispielcode

Mit dem folgenden Beispielcode werden Registrierungen in einen Notification Hub importiert.

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);

        }
    }
}

Exportieren

Das Exportieren von Registrierungen ähnelt dem Importieren mit den folgenden Unterschieden:

  • Sie benötigen lediglich die Ausgabe-URL
  • Sie erstellen eine NotificationHubJob-Klasse vom Typ „ExportRegistrations“

Beispielcodeausschnitt

Hier ist ein Beispielcodeausschnitt zum Exportieren von Registrierungen in 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;
}

Nächste Schritte

Weitere Informationen zu Registrierungen finden Sie in den folgenden Artikeln: