Share via


大量匯出及匯入 Azure 通知中樞註冊

在某些情況下,您必須在通知中心裡建立或修改大量的註冊。 例如,批次計算之後的標籤更新,或移轉現有推送實作以使用 Azure 通知中樞。

本文說明如何在通知中樞上執行大量作業,或大量匯出所有註冊。

注意: 大量匯入/匯出僅適用于「標準」定價層

高階流程

批次支援的用途,是要支援牽涉到數百萬項註冊的長時間執行工作。 若要達到此規模,批次支援會使用 Azure 儲存體來儲存工作詳細資料與輸出。 進行大量更新作業時,使用者必須在 Blob 容器中建立一個內容為註冊更新作業清單的檔案。 工作開始時,使用者會先提供輸入 Blob 的 URL,以及輸出目錄的 URL (也是在 Blob 容器中)。 在工作開始之後,使用者可查詢在工作開始時提供的 URL 位置,以查看狀態。 特定工作只能執行特定種類的作業 (建立、更新或刪除)。 匯出作業會以類似的方式執行。

匯入

設定

本節假設您已具備下列實體:

建立輸入檔案並將其儲存在 Blob 中

輸入檔案包含以 XML 序列化的註冊清單,每列一個。 下列程式碼範例會使用 Azure SDK,示範如何將註冊序列化並將其上傳至 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);
     }
}

重要

前述程式碼會序列化記憶體中的註冊,並將整個資料流上傳至 Blob 中。 若您所上傳的檔案只有幾 MB 的大小,請參閱如何執行這些步驟的 Azure Blob 指引,例如區塊 Blob

建立 URL 權杖

上傳輸入檔案之後,您必須產生 URL,以提供給通知中樞的輸入檔案與輸出目錄。 可以針對輸入與輸出使用兩種不同的 Blob 容器。

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

提交工作

有了輸入與輸出 URL 之後,即可開始進行批次工作。

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

除了輸入與輸出 URL 之外,此範例也會建立包含 JobType 物件的 NotificationHubJob 物件,這可能是下列其中一種類型:

  • ImportCreateRegistrations
  • ImportUpdateRegistrations
  • ImportDeleteRegistrations

呼叫完成之後,通知中樞會繼續執行工作,而您可以呼叫 GetNotificationHubJobAsync 以查看其狀態。

工作完成時,您可以檢視輸出目錄中的下列檔案,以檢查結果:

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

這些檔案會列出批次作業中的成功和失敗作業。 檔案格式為 .cvs;在此格式中,每一個資料列都會有原始輸入檔案的行號,以及作業的輸出 (通常是已建立或已更新的註冊描述)。

完整範例程式碼

下列範例程式碼會將註冊匯入通知中樞。

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

        }
    }
}

匯出

註冊的匯出與匯入類似,但有以下差異:

  • 您只需要輸出 URL。
  • 建立 NotificationHubJob 的 ExportRegistrations 類型。

範例程式碼片段

下列是在 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;
}

下一步

若要深入了解註冊,請參閱下列文章: