从 Windows Phone 设备向 Web 服务发送推送通知

Posted

技术标签:

【中文标题】从 Windows Phone 设备向 Web 服务发送推送通知【英文标题】:Send a push notification from a windows phone device to webservice 【发布时间】:2012-01-31 16:48:07 【问题描述】:

我有一个关于 Windows Phone 7 设备的推送通知服务的问题: 我现在可以使用 Web 应用程序向手机发送推送通知,更改磁贴的数据。但问题是:当我启动应用程序时,我需要在调试器输出中显示 URI,然后将其复制粘贴到 Web 应用程序中,然后它会联系 MPNS,这对于更新来说很好,一次到一部手机。但是我想创建一个可以自动进行多次调用的网络服务,检索应用程序的 URI(我认为在关闭和打开应用程序后会发生变化)并向其发送推送通知。但我还没有找到一个 MSDN - 处理这个的话题。他们只是使用推荐,说:“稍后用所需的 URI 替换。”所以我的问题是:我如何使用手机向网络服务发送这样的消息,响应它,然后再次连接到手机,处理这样的请求? 还有:我需要经过身份验证的网络服务,还是有调试版本?

这是我迄今为止所拥有的:

  /// <summary>
    /// Setup a connection with a webservice, in order to update a shell, either a toast- or a tile shell.
    /// </summary>
    /// <param name="shellType">The type of shell you wish to update</param>
    public void SetupShellChannel ( ShellBindType shellType )
    
        //holds the push notification that is created. Since we can only have one notification channel open at any one time, 
        //we will need to check for existance. That is why, the channelName shouldn't be changed
        HttpNotificationChannel _httpChannel = HttpNotificationChannel.Find( _channelName );

        //if the _httpChannel was not found ( read: does not exist )
        if ( _httpChannel == null )
        
            _httpChannel = new HttpNotificationChannel( _channelName  );
            _httpChannel.Open( );

            //because there is more than one shelltype we can open, we will use a switch to call the method we seek
            BindToShell( _httpChannel, shellType );
        
            //Only one push notification service is allowed per application, so we cannot send a tile notification, as well as 
            //a toast message notification. When we attempt this, we get a InvalidOperationException
        else
         
            //in this case, the _httpChannel did already exist, but the problem is, we cannot just add the eventHandlers, 
            //because there is the danger that it didn't exist, and we would get a null pointer exception.
            //_httpChannel.ChannelUriUpdated += new EventHandler<NotificationChannelUriEventArgs>( httpChannel_ChannelUriUpdated );
            //_httpChannel.ErrorOccurred += new EventHandler<NotificationChannelErrorEventArgs>( httpChannel_ErrorOccurred );

            //For testing purposes, we now display the URI to the user, and as output. Normally, we would pass this URI back to the webserver
            System.Diagnostics.Debug.WriteLine( _httpChannel.ChannelUri.ToString( ) );
        

        //if ( _httpChannel.ChannelUri )

        //When the URI is updated, we want this to be sent to the server as well, so we know that the adress has changed, 
        //and don't just send data somewhere into the void. Also, when encountering an error, we want to show the user when 
        //an error has occured.
        _httpChannel.ChannelUriUpdated += new EventHandler<NotificationChannelUriEventArgs>( HttpChannel_ChannelUriUpdated );
        _httpChannel.ErrorOccurred += new EventHandler<NotificationChannelErrorEventArgs>( HttpChannel_ErrorOccurred );
    

    //here, also we would return the URI to the server, but for debugging purposes, we display them to the user.
    void HttpChannel_ChannelUriUpdated( object sender, NotificationChannelUriEventArgs e )
    
        Deployment.Current.Dispatcher.BeginInvoke( ( ) => 
        
            System.Diagnostics.Debug.WriteLine( e.ChannelUri.ToString( ) );
            MessageBox.Show( String.Format( "the URI is 0", e.ChannelUri.ToString( ) ) );
         );
    

    private void BindToShell( HttpNotificationChannel channel, ShellBindType shellType )
    
        switch ( shellType )
        
            case ShellBindType.BindToShellTile:
                channel.BindToShellTile( );
                break;
            case ShellBindType.BindToShellToast:
                channel.BindToShellToast( );
                break;
                
    

    void HttpChannel_ErrorOccurred( object sender, NotificationChannelErrorEventArgs e )
    
        //getting an error would be caugth here, and then displayed to the user.
        Deployment.Current.Dispatcher.BeginInvoke( ( ) =>
            
                MessageBox.Show( String.Format( "A push notification 0 error occured. 1(2)3", 
                    e.ErrorType, e.Message, e.ErrorCode, e.ErrorAdditionalData ) );
             );
    

【问题讨论】:

你能解释一下qn的第一部分 - 我如何使用手机向网络服务发送这样的消息,回复它,然后再次连接到手机,处理这样的请求。 【参考方案1】:

好的,我明白你的问题。我所做的是,一旦我从 MPNS 获得了 URI,我就使用它作为参数调用服务上的 Web 方法 - 订阅(intsubscriberId, Uri channelUri);

因此,您需要确保在应用中生成subscriberId 来识别用户并将其存储在独立存储中。这可以是一个 GUID。

现在服务器有责任将订阅者到 Uri 映射保存在持久存储中。

您还需要为用户提供取消订阅的方法来选择退出推送通知。这是推送通知的认证要求之一。

现在关于您的第二个问题 - 是的,您需要保护您的服务 - 您不想处理未知请求。

我个人做的事情,分为2个服务——发布服务和订阅服务。发布服务将发送 hte 通知,而订阅将具有订阅/取消订阅方法。

【讨论】:

谢谢你的回答 =D 我已经找到了答案,并且做了类似的事情。我还没有实现这两个单独的 web 服务,这似乎是一件非常合理的事情,因为我可以管理接收通知的设备。【参考方案2】:

我猜你想问你是否可以从 Windows Phone 本身发送推送通知,而不是使用任何其他服务器端 ASP/php,如 MSDN 中的示例应用程序中所述。是的。您可以从手机/设备本身发送通知。您只需更改 MSDN 中给出的示例应用程序的发送功能。如果您有任何疑问,请回复。

static async Task<string> SendPushNotification(string textToSend)

    //You can maintain a DB to query different channel URIs of devices
    string subscriptionUri = "<Uri To Which You Want Send Notification>";
    HttpWebRequest sendNotificationRequest = (HttpWebRequest)WebRequest.Create(subscriptionUri);
    sendNotificationRequest.Method = "POST";

    string toastMessage = "<?xml version=\"1.0\" encoding=\"utf-8\"?>" +
        "<wp:Notification xmlns:wp=\"WPNotification\">" +
           "<wp:Toast>" +
                "<wp:Text1>" + textToSend + "</wp:Text1>" +
                "<wp:Param>/NotificationDetails.xaml?Message=" + textToSend + "</wp:Param>" +
           "</wp:Toast> " +
        "</wp:Notification>";
    byte[] notificationMessage = Encoding.UTF8.GetBytes(toastMessage);

    sendNotificationRequest.ContentLength = notificationMessage.Length;
    sendNotificationRequest.ContentType = "text/xml";
    sendNotificationRequest.Headers["X-WindowsPhone-Target"] = "toast";
    sendNotificationRequest.Headers["X-NotificationClass"] = "2";

    using (var requestStream = await Task.Factory.FromAsync<Stream>(sendNotificationRequest.BeginGetRequestStream, sendNotificationRequest.EndGetRequestStream, null))
    
        requestStream.Write(notificationMessage, 0, notificationMessage.Length);
    

    string notificationStatus;
    using (var response = (HttpWebResponse)(await Task<WebResponse>.Factory.FromAsync(sendNotificationRequest.BeginGetResponse, sendNotificationRequest.EndGetResponse, null)))
    
        //StreamReader reader = new StreamReader(response.GetResponseStream());
        //result = reader.ReadToEnd();
        notificationStatus = response.Headers["X-NotificationStatus"];
        MessageBox.Show(notificationStatus);
    
    return notificationStatus;

【讨论】:

以上是关于从 Windows Phone 设备向 Web 服务发送推送通知的主要内容,如果未能解决你的问题,请参考以下文章

向测试人员临时部署 Windows Phone 7 应用程序

如何从Windows Phone获取字体文件

如何使用 PushSharp 为 Windows Phone 8 设置徽章值

Windows Phone WEB API 通过 HttpClient 发布返回 404 错误

从 GPS 坐标转换为 windows phone 中的地址

处理 Windows Phone 应用中的“后退”按钮 (XAML)