企业推送架构指南Enterprise push architectural guidance

当今企业正在逐渐趋向为其最终用户(外部)或员工(内部)创建移动应用程序。Enterprises today are gradually moving towards creating mobile applications for either their end users (external) or for the employees (internal). 它们已经拥有现成的后端系统,无论是大型机还是一些 LoB 应用程序都必须集成到移动应用程序体系结构中。They have existing backend systems in place be it mainframes or some LoB applications, which must be integrated into the mobile application architecture. 本指南介绍如何最好地实现此集成,并针对常见场景建议可能的解决方案。This guide talks about how best to do this integration recommending possible solution to common scenarios.

一个常见需求是在后端系统中发生了用户感兴趣的事件时,通过其移动应用程序向用户发送推送通知。A frequent requirement is for sending push notification to the users through their mobile application when an event of interest occurs in the backend systems. 例如,某位在 iPhone 上安装了银行的银行应用的客户想要在记入其帐户的借方金额超过特定值时收到通知,或者在 Intranet 方案中,某位在 Windows Phone 上安装了预算审批应用的财务部门员工,希望在收到审批请求时获得通知。For example, a bank customer who has the bank's banking app on an iPhone wants to be notified when a debit is made above a certain amount from the account or an intranet scenario where an employee from finance department who has a budget approval app on a Windows Phone wants to be notified when the approval request is received.

银行帐户或审批处理很可能要在某个后端系统中完成,该系统必须启动到用户的推送。The bank account or approval processing is likely to be done in some backend system, which must initiate a push to the user. 可能有多个此类后端系统,所有这些系统在事件触发通知时都必须生成同样的逻辑来进行推送。There may be multiple such backend systems, which must all build the same kind of logic to push when an event triggers a notification. 此处的复杂性在于将多个后端系统与单个推送系统集成在一起,在此系统中,最终用户可能已订阅不同的通知,甚至可能存在多个移动应用程序。The complexity here lies in integrating several backend systems together with a single push system where the end users may have subscribed to different notifications and there may even be multiple mobile applications. 例如,对于 Intranet 移动应用来说,一个移动应用程序可能需要从多个此类后端系统接收通知。For example, intranet mobile apps where one mobile application may want to receive notifications from multiple such backend systems. 后端系统不知道或不需要知道推送语义/技术,因此常见的解决方案是引入一个组件,该组件轮询后端系统是否存在任何相关事件并负责将推送消息发送到客户端。The backend systems do not know or need to know of push semantics/technology so a common solution here traditionally has been to introduce a component, which polls the backend systems for any events of interest and is responsible for sending the push messages to the client.

更好的解决方案是使用 Azure 服务总线 - 主题/订阅模型,该模型会降低复杂性,同时使解决方案可扩展。A better solution is to use Azure Service Bus - Topic/Subscription model, which reduces the complexity while making the solution scalable.

下面是该解决方案的一般体系结构(普遍用于多个移动应用,但在只有一个移动应用时也同样适用)Here is the general architecture of the solution (generalized with multiple mobile apps but equally applicable when there is only one mobile app)

体系结构Architecture

显示事件、订阅和推送消息流的企业体系结构关系图。

此体系结构图中的关键部分是 Azure 服务总线,它提供了主题/订阅编程模型(可在服务总线 Pub/Sub 编程中找到有关它的更多内容)。The key piece in this architectural diagram is Azure Service Bus, which provides a topics/subscriptions programming model (more on it at Service Bus Pub/Sub programming). 接收方,在本示例中是移动后端(通常是 Azure 移动服务,它会启动到移动应用的推送)不直接从后端系统接收消息,而是改用 Azure 服务总线提供的中间抽象层,移动后端通过它可从一个或多个后端系统接收消息。The receiver, which in this case, is the Mobile backend (typically Azure Mobile Service, which initiates a push to the mobile apps) does not receive messages directly from the backend systems but instead, an intermediate abstraction layer provided by Azure Service Bus, which enables mobile backend to receive messages from one or more backend systems. 需要为每个后端系统创建服务总线主题,例如帐户、人力资源、财务等,这些基本上都是相关“主题”,会启动要作为推送通知发送的消息。A Service Bus Topic needs to be created for each of the backend systems, for example, Account, HR, Finance, which is basically "topics" of interest, which initiates messages to be sent as push notification. 后端系统会向这些主题发送消息。The backend systems send messages to these topics. 移动后端可以通过创建服务总线订阅来订阅一个或多个此类主题。A Mobile Backend can subscribe to one or more such topics by creating a Service Bus subscription. 这会授权移动后端从相应的后端系统接收通知。It entitles the mobile backend to receive a notification from the corresponding backend system. 移动后端将继续在其订阅上侦听消息,一条消息到达后,它将立即返回并将该消息作为通知发送到通知中心。Mobile backend continues to listen for messages on their subscriptions and as soon as a message arrives, it turns back and sends it as notification to its notification hub. 然后,通知中心最终将该消息传送到移动应用。Notification hubs then eventually deliver the message to the mobile app. 下面是关键组件列表:Here is the list of key components:

  1. 后端系统(LoB/旧系统)Backend systems (LoB/Legacy systems)
    • 创建服务总线主题Creates Service Bus Topic
    • 发送消息Sends Message
  2. 移动后端Mobile backend
    • 创建服务订阅Creates Service Subscription
    • 接收消息(来自后端系统)Receives Message (from Backend system)
    • 将通知发送到客户端(通过 Azure 通知中心)Sends notification to clients (via Azure Notification Hub)
  3. 移动 应用程序Mobile Application
    • 接收并显示通知Receives and display notification

优点Benefits

  1. 接收方(通过通知中心的移动应用/服务)和发送方(后端系统)之间的这种解耦使得只需要最小的更改即可集成其他后端系统。The decoupling between the receiver (mobile app/service via Notification Hub) and sender (backend systems) enables additional backend systems being integrated with minimal change.
  2. 这还使得采用多个移动应用的方案能够从一个或多个后端系统接收事件。It also makes the scenario of multiple mobile apps being able to receive events from one or more backend systems.

示例Sample

先决条件Prerequisites

完成以下教程,熟悉相关概念以及常见的创建和配置步骤:Complete the following tutorials to familiarize with the concepts as well as common creation & configuration steps:

  1. 服务总线 Pub/Sub 编程 - 此教程说明了使用服务总线主题/订阅的详细信息、如何创建命名空间以包含主题/订阅、如何通过它们发送和接收消息。Service Bus Pub/Sub programming - This tutorial explains the details of working with Service Bus Topics/Subscriptions, how to create a namespace to contain topics/subscriptions, how to send & receive messages from them.
  2. 通知中心 - Windows 通用教程 - 此教程说明了如何设置 Windows 应用商店应用以及如何使用通知中心注册,并接收通知。Notification Hubs - Windows Universal tutorial - This tutorial explains how to set up a Windows Store app and use Notification Hubs to register and then receive notifications.

代码示例Sample code

完整的示例代码可在通知中心示例中找到。The full sample code is available at Notification Hub Samples. 它分为三个组件:It is split into three components:

  1. EnterprisePushBackendSystemEnterprisePushBackendSystem

    a.a. 此项目使用 WindowsAzure.ServiceBus NuGet 包,并基于服务总线 Pub/Sub 编程构建。This project uses the WindowsAzure.ServiceBus NuGet package and is based on Service Bus Pub/Sub programming.

    b.b. 此应用程序是一个简单的 C# 控制台应用,可模拟启动要传送到移动应用的消息的 LoB 系统。This application is a simple C# console app to simulate an LoB system, which initiates the message to be delivered to the mobile app.

    static void Main(string[] args)
    {
        string connectionString =
            CloudConfigurationManager.GetSetting("Microsoft.ServiceBus.ConnectionString");
    
        // Create the topic
        CreateTopic(connectionString);
    
        // Send message
        SendMessage(connectionString);
    }
    

    c.c. CreateTopic 用于创建服务总线主题。CreateTopic is used to create the Service Bus topic.

    public static void CreateTopic(string connectionString)
    {
        // Create the topic if it does not exist already
    
        var namespaceManager =
            NamespaceManager.CreateFromConnectionString(connectionString);
    
        if (!namespaceManager.TopicExists(sampleTopic))
        {
            namespaceManager.CreateTopic(sampleTopic);
        }
    }
    

    d.d. SendMessage 用于将消息发送到此服务总线主题。SendMessage is used to send the messages to this Service Bus Topic. 出于本示例的目的,此代码只定期向此主题发送一组随机消息。This code simply sends a set of random messages to the topic periodically for the purpose of the sample. 通常会有在事件发生时发送消息的后端系统。Normally there is a backend system, which sends messages when an event occurs.

    public static void SendMessage(string connectionString)
    {
        TopicClient client =
            TopicClient.CreateFromConnectionString(connectionString, sampleTopic);
    
        // Sends random messages every 10 seconds to the topic
        string[] messages =
        {
            "Employee Id '{0}' has joined.",
            "Employee Id '{0}' has left.",
            "Employee Id '{0}' has switched to a different team."
        };
    
        while (true)
        {
            Random rnd = new Random();
            string employeeId = rnd.Next(10000, 99999).ToString();
            string notification = String.Format(messages[rnd.Next(0,messages.Length)], employeeId);
    
            // Send Notification
            BrokeredMessage message = new BrokeredMessage(notification);
            client.Send(message);
    
            Console.WriteLine("{0} Message sent - '{1}'", DateTime.Now, notification);
    
            System.Threading.Thread.Sleep(new TimeSpan(0, 0, 10));
        }
    }
    
  2. ReceiveAndSendNotificationReceiveAndSendNotification

    a.a. 此项目使用 WindowsAzure.ServiceBus 和 Microsoft.Web.WebJobs.Publish NuGet 包,并基于服务总线 Pub/Sub 编程构建。This project uses the WindowsAzure.ServiceBus and Microsoft.Web.WebJobs.Publish NuGet packages and is based on Service Bus Pub/Sub programming.

    b.b. 以下控制台应用作为 Azure WebJob 运行,因为它必须连续运行以侦听来自 LoB/后端系统的消息。The following console app runs as an Azure WebJob since it has to run continuously to listen for messages from the LoB/backend systems. 此应用程序是移动后端的一部分。This application is part of your Mobile backend.

    static void Main(string[] args)
    {
        string connectionString =
                 CloudConfigurationManager.GetSetting("Microsoft.ServiceBus.ConnectionString");
    
        // Create the subscription that receives messages
        CreateSubscription(connectionString);
    
        // Receive message
        ReceiveMessageAndSendNotification(connectionString);
    }
    

    c.c. CreateSubscription 用于为后端系统发送消息的主题创建服务总线订阅。CreateSubscription is used to create a Service Bus subscription for the topic where the backend system sends messages. 根据业务方案,该组件会创建符合相应主题的一个或多个订阅(例如,一些用户可以从人力资源系统接收消息,一些可从财务系统接收消息,等等)Depending on the business scenario, this component creates one or more subscriptions to corresponding topics (for example, some may be receiving messages from HR system, some from Finance system, and so on)

    static void CreateSubscription(string connectionString)
    {
        // Create the subscription if it does not exist already
        var namespaceManager =
            NamespaceManager.CreateFromConnectionString(connectionString);
    
        if (!namespaceManager.SubscriptionExists(sampleTopic, sampleSubscription))
        {
            namespaceManager.CreateSubscription(sampleTopic, sampleSubscription);
        }
    }
    

    d.d. ReceiveMessageAndSendNotification 用于使用其订阅从主题中读取消息,如果读取成功,则会制作要使用 Azure 通知中心发送到移动应用程序的通知(在示例方案中为 Windows 本机 toast 通知)。ReceiveMessageAndSendNotification is used to read the message from the topic using its subscription and if the read is successful then craft a notification (in the sample scenario a Windows native toast notification) to be sent to the mobile application using Azure Notification Hubs.

    static void ReceiveMessageAndSendNotification(string connectionString)
    {
        // Initialize the Notification Hub
        string hubConnectionString = CloudConfigurationManager.GetSetting
                ("Microsoft.NotificationHub.ConnectionString");
        hub = NotificationHubClient.CreateClientFromConnectionString
                (hubConnectionString, "enterprisepushservicehub");
    
        SubscriptionClient Client =
            SubscriptionClient.CreateFromConnectionString
                    (connectionString, sampleTopic, sampleSubscription);
    
        Client.Receive();
    
        // Continuously process messages received from the subscription
        while (true)
        {
            BrokeredMessage message = Client.Receive();
            var toastMessage = @"<toast><visual><binding template=""ToastText01""><text id=""1"">{messagepayload}</text></binding></visual></toast>";
    
            if (message != null)
            {
                try
                {
                    Console.WriteLine(message.MessageId);
                    Console.WriteLine(message.SequenceNumber);
                    string messageBody = message.GetBody<string>();
                    Console.WriteLine("Body: " + messageBody + "\n");
    
                    toastMessage = toastMessage.Replace("{messagepayload}", messageBody);
                    SendNotificationAsync(toastMessage);
    
                    // Remove message from subscription
                    message.Complete();
                }
                catch (Exception)
                {
                    // Indicate a problem, unlock message in subscription
                    message.Abandon();
                }
            }
        }
    }
    static async void SendNotificationAsync(string message)
    {
        await hub.SendWindowsNativeNotificationAsync(message);
    }
    

    e.e. 要将此应用发布为 WebJob,请右键单击 Visual Studio 中的解决方案,然后选择“发布为 WebJob”********For publishing this app as a WebJob, right click on the solution in Visual Studio and select Publish as WebJob

    显示的右键单击选项的屏幕截图,其中“发布为 Azure Web 作业”以红色标出。

    f.f. 选择发布配置文件并创建新的 Azure 网站(如果它尚未存在),该网站会托管此 WebJob,拥有该网站后,单击“发布”****。Select your publishing profile and create a new Azure WebSite if it does not exist already, which hosts this WebJob and once you have the WebSite then Publish.

    显示在 Azure 上创建网站的工作流的屏幕截图。

    “发布 Web”对话框的屏幕截图,其中已选中 Microsoft Azure 网站选项,有一个绿色箭头指向“选择现有网站”对话框,“新建”选项以红色标出,还有一个绿色箭头指向“在 Microsoft Azure 上创建网站”对话框,网站名称和“创建”选项以红色标出。Screenshot of the Publish Web dialog box with the Microsoft Azure Websites option selected, a green arrow pointing to the Select Existing Website dialog box with the New option outlined in red, and a green arrow pointing to the Create site on Microsoft Azure dialog box with the Site name and Create options outlined in red.

    g.g. 将该作业配置为“连续运行”,以便在登录到 Azure 门户时,可看到如下内容:Configure the job to be "Run Continuously" so that when you log in to the Azure portal you should see something like the following:

    Azure 门户的屏幕截图,其中显示了企业推送后端 Web 作业,名称、计划和日志值以红色标出。

  3. EnterprisePushMobileAppEnterprisePushMobileApp

    a.a. 此应用程序一个 Windows 应用商店应用程序,它从作为移动后端的一部分运行的 WebJob 接收 toast 通知并显示。This application is a Windows Store application, which receives toast notifications from the WebJob running as part of your Mobile backend and display it. 此代码基于通知中心 - Windows 通用教程构建。This code is based on Notification Hubs - Windows Universal tutorial.

    b.b. 确保应用程序已启用接收 toast 通知。Ensure that your application is enabled to receive toast notifications.

    c.c. 确保在应用启动时(替换 HubNameDefaultListenSharedAccessSignature 值后)调用以下通知中心注册代码:Ensure that the following Notification Hubs registration code is being called at the App start up (after replacing the HubName and DefaultListenSharedAccessSignature values:

    private async void InitNotificationsAsync()
    {
        var channel = await PushNotificationChannelManager.CreatePushNotificationChannelForApplicationAsync();
    
        var hub = new NotificationHub("[HubName]", "[DefaultListenSharedAccessSignature]");
        var result = await hub.RegisterNativeAsync(channel.Uri);
    
        // Displays the registration ID so you know it was successful
        if (result.RegistrationId != null)
        {
            var dialog = new MessageDialog("Registration successful: " + result.RegistrationId);
            dialog.Commands.Add(new UICommand("OK"));
            await dialog.ShowAsync();
        }
    }
    

运行示例Running the sample

  1. 确保 WebJob 成功运行并且计划为“连续运行”。Ensure that your WebJob is running successfully and scheduled to run continuously.

  2. 运行 EnterprisePushMobileApp,这可启动 Windows 应用商店应用。Run the EnterprisePushMobileApp, which starts the Windows Store app.

  3. 运行 EnterprisePushBackendSystem 控制台应用程序,这可模拟 LoB 后端并开始发送消息,应该出现如下图所示的 toast 通知****:Run the EnterprisePushBackendSystem console application, which simulates the LoB backend and starts sending messages and you should see toast notifications appearing like the following image:

    运行企业推送后端系统应用的控制台以及应用发送的消息的屏幕截图。

  4. 这些消息最初会发送到由 Web 作业中的服务总线订阅监视的服务总线主题。The messages were originally sent to Service Bus topics, which was being monitored by Service Bus subscriptions in your Web Job. 收到消息后,将创建通知并将其发送到移动应用。Once a message was received, a notification was created and sent to the mobile app. 转到 Azure 门户中 Web 作业的“日志”链接时,可以仔细查看 Web 作业日志来确认处理:You can look through the WebJob logs to confirm the processing when you go to the Logs link in Azure portal for your Web Job:

    “连续 Web 作业详细信息”对话框的屏幕截图,其中发送的信息以红色标出。