注册管理Registration management

本主题说明如何向通知中心注册设备以接收推送通知。This topic explains how to register devices with notification hubs in order to receive push notifications. 本主题将概要介绍注册,并介绍注册设备的两种主要模式:直接从设备向通知中心注册,以及通过应用程序后端注册。The topic describes registrations at a high level, then introduces the two main patterns for registering devices: registering from the device directly to the notification hub, and registering through an application backend.

什么是设备注册What is device registration

向通知中心注册设备是通过使用“注册”或“安装”来完成的 。Device registration with a Notification Hub is accomplished using a Registration or Installation.

注册Registrations

注册将设备的平台通知服务 (PNS) 句柄与标记(有时还包括模板)相关联。A registration associates the Platform Notification Service (PNS) handle for a device with tags and possibly a template. PNS 句柄可能是 ChannelURI、设备令牌。The PNS handle could be a ChannelURI, device token. 标记用于将通知路由到一组正确的设备句柄。Tags are used to route notifications to the correct set of device handles. 有关详细信息,请参阅路由和标记表达式For more information, see Routing and Tag Expressions. 模板用于实现按注册转换。Templates are used to implement per-registration transformation. 有关详细信息,请参阅模板For more information, see Templates.

备注

Azure 通知中心支持每个设备注册最多 60 个标记。Azure Notification Hubs supports a maximum of 60 tags per device.

安装Installations

安装是增强型的注册,包含推送相关的属性包。An Installation is an enhanced registration that includes a bag of push related properties. 它是最新且最佳的设备注册方式。It is the latest and best approach to registering your devices. 但是,客户端 .NET SDK(用于后端操作的通知中心 SDK)目前不支持安装。However, it is not supported by client-side .NET SDK (Notification Hub SDK for backend operations) as of yet. 这意味着,如果要从客户端设备本身注册,则必须使用 通知中心 REST API 方法来支持安装。This means if you are registering from the client device itself, you would have to use the Notification Hubs REST API approach to support installations. 如果使用后端服务,则应能够使用 用于后端操作的通知中心 SDKIf you are using a backend service, you should be able to use Notification Hub SDK for backend operations.

以下是使用安装的一些主要优点:The following are some key advantages to using installations:

  • 创建或更新安装是完全幂等的。Creating or updating an installation is fully idempotent. 因此可以重试该操作,而不需要顾虑重复注册的情况。So you can retry it without any concerns about duplicate registrations.
  • 此安装模型支持特殊的标记格式 ($InstallationId:{INSTALLATION_ID}),该格式允许将通知直接发送到特定的设备。The installation model supports a special tag format ($InstallationId:{INSTALLATION_ID}) that enables sending a notification directly to the specific device. 例如,如果应用的代码为此特定设备设置了安装 ID joe93developer,则开发人员在向 $InstallationId:{joe93developer} 标记发送通知时,可以将此设备作为目标。For example, if the app's code sets an installation ID of joe93developer for this particular device, a developer can target this device when sending a notification to the $InstallationId:{joe93developer} tag. 这样,无需编写任何额外的代码,就能将特定设备作为目标。This enables you to target a specific device without having to do any additional coding.
  • 使用安装还能执行部分注册更新。Using installations also enables you to do partial registration updates. 可以使用 JSON-Patch standard以 PATCH 方法来请求部分安装更新。The partial update of an installation is requested with a PATCH method using the JSON-Patch standard. 想要更新注册中的标记时,此方法很有用。This is useful when you want to update tags on the registration. 用户不需要删除整个注册,并重新发送前面的所有标记。You don't have to pull down the entire registration and then resend all the previous tags again.

安装可包含以下属性。An installation can contain the following properties. 有关完整的安装属性列表,请参阅使用 REST API 创建或覆盖安装安装属性For a complete listing of the installation properties, see Create or Overwrite an Installation with REST API or Installation Properties.

// Example installation format to show some supported properties
{
    installationId: "",
    expirationTime: "",
    tags: [],
    platform: "",
    pushChannel: "",
    ………
    templates: {
        "templateName1" : {
            body: "",
            tags: [] },
        "templateName2" : {
            body: "",
            // Headers are for Windows Store only
            headers: {
                "X-WNS-Type": "wns/tile" }
            tags: [] }
    },
    secondaryTiles: {
        "tileId1": {
            pushChannel: "",
            tags: [],
            templates: {
                "otherTemplate": {
                    bodyTemplate: "",
                    headers: {
                        ... }
                    tags: [] }
            }
        }
    }
}

备注

默认情况下,注册和安装不会过期。By default, registrations and installations do not expire.

注册与安装必须包含每个设备/通道的有效 PNS 句柄。Registrations and installations must contain a valid PNS handle for each device/channel. 由于只能在设备上的客户端应用中获取 PNS 句柄,因此有一种模式是直接在该设备上使用客户端应用进行注册。Because PNS handles can only be obtained in a client app on the device, one pattern is to register directly on that device with the client app. 另一方面,与标记相关的安全性考虑和业务逻辑可能要求在应用后端管理设备注册。On the other hand, security considerations and business logic related to tags might require you to manage device registration in the app back-end.

备注

安装 API 不支持百度服务(尽管注册 API 支持)。The Installations API does not support the Baidu service (although the Registrations API does).

模板Templates

如果要使用模板,则设备安装还会保存与设备关联的、采用 JSON 格式的所有模板(请参阅上面的示例)。If you want to use Templates, the device installation also holds all templates associated with that device in a JSON format (see sample above). 模板名称有助于将目标指向相同设备的不同模板。The template names help target different templates for the same device.

每个模板名称会映射到一个模板主体和一组可选标记。Each template name maps to a template body and an optional set of tags. 此外,每个平台可能有附加的模板属性。Moreover, each platform can have additional template properties. 对于 Windows 应用商店(使用 WNS)和 Windows Phone 8(使用 MPNS),模板中还可能会有一组附加标头。For Windows Store (using WNS) and Windows Phone 8 (using MPNS), an additional set of headers can be part of the template. 对于 APNs,可以将过期属性设为常量或模板表达式。In the case of APNs, you can set an expiry property to either a constant or to a template expression. 有关完整的安装属性列表,请参阅 使用 REST 创建或覆盖安装 主题。For a complete listing of the installation properties see, Create or Overwrite an Installation with REST topic.

Windows 应用商店应用的辅助磁贴Secondary Tiles for Windows Store Apps

对于 Windows 应用商店客户端应用程序,将通知发送到辅助磁贴与将通知发送到主磁贴相同。For Windows Store client applications, sending notifications to secondary tiles is the same as sending them to the primary one. 安装中也支持此行为。This is also supported in installations. 辅助磁贴具有不同的 ChannelUri,客户端应用上的 SDK 会以透明方式处理此 ChannelUri。Secondary tiles have a different ChannelUri, which the SDK on your client app handles transparently.

SecondaryTiles 字典使用的 TileId 与在 Windows 应用商店应用中创建 SecondaryTiles 时使用的 TileId 相同。The SecondaryTiles dictionary uses the same TileId that is used to create the SecondaryTiles object in your Windows Store app. 与主 ChannelUri 一样,辅助磁贴的 ChannelUri 可随时更改。As with the primary ChannelUri, ChannelUris of secondary tiles can change at any moment. 为了使通知中心中的安装保持更新,设备必须使用辅助磁贴的当前 ChannelUri 刷新这些安装。In order to keep the installations in the notification hub updated, the device must refresh them with the current ChannelUris of the secondary tiles.

从设备管理注册Registration management from the device

从客户端应用管理设备注册时,后端只负责发送通知。When managing device registration from client apps, the backend is only responsible for sending notifications. 客户端应用使 PNS 句柄保持最新状态,并且会注册标记。Client apps keep PNS handles up-to-date, and register tags. 下图演示了此模式。The following picture illustrates this pattern.

从设备注册

设备首先从 PNS 检索 PNS 句柄,然后直接向通知中心进行注册。The device first retrieves the PNS handle from the PNS, then registers with the notification hub directly. 注册成功之后,应用后端即可发送以该注册为目标的通知。After the registration is successful, the app backend can send a notification targeting that registration. 有关如何发送通知的详细信息,请参阅路由和标记表达式For more information about how to send notifications, see Routing and Tag Expressions.

在此情况下,只可使用“侦听”权限从设备访问通知中心。In this case, you use only Listen rights to access your notification hubs from the device. 有关详细信息,请参阅安全性For more information, see Security.

从设备注册是最简单的方法,但存在一些缺点:Registering from the device is the simplest method, but it has some drawbacks:

  • 客户端应用只能在它处于活动状态时更新其标记。A client app can only update its tags when the app is active. 例如,如果用户有两台设备要注册与体育团队相关的标记,则当第一台设备注册附加标记(例如,Seahawks)时,第二台设备将不会收到有关 Seahawks 的通知,直到第二次在第二台设备上执行应用程序为止。For example, if a user has two devices that register tags related to sport teams, when the first device registers for an additional tag (for example, Seahawks), the second device will not receive the notifications about the Seahawks until the app on the second device is executed a second time. 更概括地说,如果标记受多个设备的影响,则从后端管理标记是理想的选择。More generally, when tags are affected by multiple devices, managing tags from the backend is a desirable option.
  • 由于应用可能会受到攻击,因此保护特定标记的注册需要格外小心,如“标记级安全性”部分中所述。Since apps can be hacked, securing the registration to specific tags requires extra care, as explained in the section “Tag-level security.”

使用安装从设备向通知中心注册的示例代码Example code to register with a notification hub from a device using an installation

此时,仅支持使用 通知中心 REST API执行此操作。At this time, this is only supported using the Notification Hubs REST API.

也可以使用 JSON-Patch standard 以 PATCH 方法更新安装。You can also use the PATCH method using the JSON-Patch standard for updating the installation.

class DeviceInstallation
{
    public string installationId { get; set; }
    public string platform { get; set; }
    public string pushChannel { get; set; }
    public string[] tags { get; set; }
}

private async Task<HttpStatusCode> CreateOrUpdateInstallationAsync(DeviceInstallation deviceInstallation,
        string hubName, string listenConnectionString)
{
    if (deviceInstallation.installationId == null)
        return HttpStatusCode.BadRequest;

    // Parse connection string (https://msdn.microsoft.com/library/azure/dn495627.aspx)
    ConnectionStringUtility connectionSaSUtil = new ConnectionStringUtility(listenConnectionString);
    string hubResource = "installations/" + deviceInstallation.installationId + "?";
    string apiVersion = "api-version=2015-04";

    // Determine the targetUri that we will sign
    string uri = connectionSaSUtil.Endpoint + hubName + "/" + hubResource + apiVersion;

    //=== Generate SaS Security Token for Authorization header ===
    // See, https://msdn.microsoft.com/library/azure/dn495627.aspx
    string SasToken = connectionSaSUtil.getSaSToken(uri, 60);

    using (var httpClient = new HttpClient())
    {
        string json = JsonConvert.SerializeObject(deviceInstallation);

        httpClient.DefaultRequestHeaders.Add("Authorization", SasToken);

        var response = await httpClient.PutAsync(uri, new StringContent(json, System.Text.Encoding.UTF8, "application/json"));
        return response.StatusCode;
    }
}

var channel = await PushNotificationChannelManager.CreatePushNotificationChannelForApplicationAsync();

string installationId = null;
var settings = ApplicationData.Current.LocalSettings.Values;

// If we have not stored an installation id in application data, create and store as application data.
if (!settings.ContainsKey("__NHInstallationId"))
{
    installationId = Guid.NewGuid().ToString();
    settings.Add("__NHInstallationId", installationId);
}

installationId = (string)settings["__NHInstallationId"];

var deviceInstallation = new DeviceInstallation
{
    installationId = installationId,
    platform = "wns",
    pushChannel = channel.Uri,
    //tags = tags.ToArray<string>()
};

var statusCode = await CreateOrUpdateInstallationAsync(deviceInstallation, 
                    "<HUBNAME>", "<SHARED LISTEN CONNECTION STRING>");

if (statusCode != HttpStatusCode.Accepted)
{
    var dialog = new MessageDialog(statusCode.ToString(), "Registration failed. Installation Id : " + installationId);
    dialog.Commands.Add(new UICommand("OK"));
    await dialog.ShowAsync();
}
else
{
    var dialog = new MessageDialog("Registration successful using installation Id : " + installationId);
    dialog.Commands.Add(new UICommand("OK"));
    await dialog.ShowAsync();
}

使用注册从设备向通知中心注册的示例代码Example code to register with a notification hub from a device using a registration

这些方法为调用它们的设备创建或更新注册。These methods create or update a registration for the device on which they are called. 这意味着,若要更新句柄或标记,必须覆盖整个注册。This means that in order to update the handle or the tags, you must overwrite the entire registration. 请记住,注册是暂时性的,因此,始终应使用具有特定设备所需的当前标记的可靠存储。Remember that registrations are transient, so you should always have a reliable store with the current tags that a specific device needs.

// Initialize the Notification Hub
NotificationHubClient hub = NotificationHubClient.CreateClientFromConnectionString(listenConnString, hubName);

// The Device id from the PNS
var pushChannel = await PushNotificationChannelManager.CreatePushNotificationChannelForApplicationAsync();

// If you are registering from the client itself, then store this registration id in device
// storage. Then when the app starts, you can check if a registration id already exists or not before
// creating.
var settings = ApplicationData.Current.LocalSettings.Values;

// If we have not stored a registration id in application data, store in application data.
if (!settings.ContainsKey("__NHRegistrationId"))
{
    // make sure there are no existing registrations for this push handle (used for iOS and Android)    
    string newRegistrationId = null;
    var registrations = await hub.GetRegistrationsByChannelAsync(pushChannel.Uri, 100);
    foreach (RegistrationDescription registration in registrations)
    {
        if (newRegistrationId == null)
        {
            newRegistrationId = registration.RegistrationId;
        }
        else
        {
            await hub.DeleteRegistrationAsync(registration);
        }
    }

    newRegistrationId = await hub.CreateRegistrationIdAsync();

    settings.Add("__NHRegistrationId", newRegistrationId);
}

string regId = (string)settings["__NHRegistrationId"];

RegistrationDescription registration = new WindowsRegistrationDescription(pushChannel.Uri);
registration.RegistrationId = regId;
registration.Tags = new HashSet<string>(YourTags);

try
{
    await hub.CreateOrUpdateRegistrationAsync(registration);
}
catch (Microsoft.WindowsAzure.Messaging.RegistrationGoneException e)
{
    settings.Remove("__NHRegistrationId");
}

从后端管理注册Registration management from a backend

从后端管理注册需要编写附加代码。Managing registrations from the backend requires writing additional code. 每次设备中的应用启动时,该应用都必须为后端提供已更新的 PNS 句柄(以及标记和模板),然后后端必须在通知中心上更新此句柄。The app from the device must provide the updated PNS handle to the backend every time the app starts (along with tags and templates), and the backend must update this handle on the notification hub. 下图演示了此设计。The following picture illustrates this design.

注册管理

从后端管理注册的优点是即使在设备上的相应应用处于非活动状态也能修改注册标记,并且在向其注册添加标记之前能够对客户端应用进行身份验证。The advantages of managing registrations from the backend include the ability to modify tags to registrations even when the corresponding app on the device is inactive, and to authenticate the client app before adding a tag to its registration.

使用安装从后端向通知中心注册的示例代码Example code to register with a notification hub from a backend using an installation

客户端设备仍会像前面一样获取其 PNS 句柄及相关的安装属性,然后在可以执行注册和授权标记等的后端上调用自定义 API。后端可以利用适用于后端操作的通知中心 SDKThe client device still gets its PNS handle and relevant installation properties as before and calls a custom API on the backend that can perform the registration and authorize tags etc. The backend can leverage the Notification Hub SDK for backend operations.

也可以使用 JSON-Patch standard 以 PATCH 方法更新安装。You can also use the PATCH method using the JSON-Patch standard for updating the installation.

// Initialize the Notification Hub
NotificationHubClient hub = NotificationHubClient.CreateClientFromConnectionString(listenConnString, hubName);

// Custom API on the backend
public async Task<HttpResponseMessage> Put(DeviceInstallation deviceUpdate)
{

    Installation installation = new Installation();
    installation.InstallationId = deviceUpdate.InstallationId;
    installation.PushChannel = deviceUpdate.Handle;
    installation.Tags = deviceUpdate.Tags;

    switch (deviceUpdate.Platform)
    {
        case "mpns":
            installation.Platform = NotificationPlatform.Mpns;
            break;
        case "wns":
            installation.Platform = NotificationPlatform.Wns;
            break;
        case "apns":
            installation.Platform = NotificationPlatform.Apns;
            break;
        default:
            throw new HttpResponseException(HttpStatusCode.BadRequest);
    }


    // In the backend we can control if a user is allowed to add tags
    //installation.Tags = new List<string>(deviceUpdate.Tags);
    //installation.Tags.Add("username:" + username);

    await hub.CreateOrUpdateInstallationAsync(installation);

    return Request.CreateResponse(HttpStatusCode.OK);
}

使用注册 ID 从设备向通知中心注册的示例代码Example code to register with a notification hub from a device using a registration ID

从应用后端可以对注册执行基本 CRUDS 操作。From your app backend, you can perform basic CRUDS operations on registrations. 例如:For example:

var hub = NotificationHubClient.CreateClientFromConnectionString("{connectionString}", "hubName");

// create a registration description object of the correct type, e.g.
var reg = new WindowsRegistrationDescription(channelUri, tags);

// Create
await hub.CreateRegistrationAsync(reg);

// Get by id
var r = await hub.GetRegistrationAsync<RegistrationDescription>("id");

// update
r.Tags.Add("myTag");

// update on hub
await hub.UpdateRegistrationAsync(r);

// delete
await hub.DeleteRegistrationAsync(r);

后端必须处理注册更新之间的并发性。The backend must handle concurrency between registration updates. 服务总线为注册管理提供了乐观并发控制。Service Bus offers optimistic concurrency control for registration management. 在 HTTP 级别,这是通过对注册管理操作使用 ETag 来实现的。At the HTTP level, this is implemented with the use of ETag on registration management operations. Microsoft SDK 以透明方式使用此功能,如果由于并发原因拒绝了更新,则会引发异常。This feature is transparently used by Microsoft SDKs, which throw an exception if an update is rejected for concurrency reasons. 应用后端负责处理这些异常并在需要时重试更新。The app backend is responsible for handling these exceptions and retrying the update if necessary.