/WP7.1/Templates/VB/WPCloud.Mem/WindowsPhoneCloud.Web/Controllers/PushNotificationsController.vb
Visual Basic | 267 lines | 193 code | 49 blank | 25 comment | 2 complexity | 1da1520948c2bab0076c45728568a64f MD5 | raw file
- ' ----------------------------------------------------------------------------------
- ' Microsoft Developer & Platform Evangelism
- '
- ' Copyright (c) Microsoft Corporation. All rights reserved.
- '
- ' THIS CODE AND INFORMATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND,
- ' EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES
- ' OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE.
- ' ----------------------------------------------------------------------------------
- ' The example companies, organizations, products, domain names,
- ' e-mail addresses, logos, people, places, and events depicted
- ' herein are fictitious. No association with any real company,
- ' organization, product, domain name, email address, logo, person,
- ' places, or events is intended or should be inferred.
- ' ----------------------------------------------------------------------------------
-
- Imports WindowsPhone.Recipes.Push.Messages
- Imports Microsoft.WindowsAzure.StorageClient
- Imports Microsoft.WindowsAzure
- Imports Microsoft.Samples.WindowsPhoneCloud.Web.UserAccountWrappers
- Imports Microsoft.Samples.WindowsPhoneCloud.Web.Models
- Imports Microsoft.Samples.WindowsPhoneCloud.Web.Infrastructure
- Imports System.Security.Cryptography.X509Certificates
- Imports System.Security.Authentication
- Imports System.Net.Sockets
- Imports System.Net.Security
- Imports System.IO
- Imports System.Globalization
-
- Namespace Controllers
- <CustomAuthorize(Roles:=PrivilegeConstants.AdminPrivilege)>
- Public Class PushNotificationsController
- Inherits Controller
- Private Const DefaultPort As Integer = 2195
-
- Private ReadOnly cloudQueueClient As CloudQueueClient
- Private ReadOnly pushUserEndpointsRepository As IPushUserEndpointsRepository
-
- #If ACS Then
- Private ReadOnly userRepository As IUserRepository
-
- Public Sub New()
- Me.New(Nothing, New UserTablesServiceContext(), New UserTablesServiceContext())
- End Sub
-
- <CLSCompliant(False)> _
- Public Sub New(ByVal cloudQueueClient As CloudQueueClient, ByVal pushUserEndpointsRepository As IPushUserEndpointsRepository, ByVal userRepository As IUserRepository)
- If GetStorageAccountFromConfigurationSetting() Is Nothing Then
- If cloudQueueClient Is Nothing Then
- Throw New ArgumentNullException("cloudQueueClient", "Cloud Queue Client cannot be null if no configuration is loaded.")
- End If
- End If
-
- Me.cloudQueueClient = If(cloudQueueClient, GetStorageAccountFromConfigurationSetting().CreateCloudQueueClient())
- Me.userRepository = userRepository
- Me.pushUserEndpointsRepository = pushUserEndpointsRepository
- End Sub
-
- Public Function Microsoft() As ActionResult
- Dim users = Me.pushUserEndpointsRepository.GetAllPushUsers().Select(Function(userId) New UserModel With {.UserId = userId, .UserName = Me.userRepository.GetUser(userId).Name})
-
- Return Me.View(users)
- End Function
- #Else
- Private ReadOnly membershipService As IMembershipService
-
- Public Sub New()
- Me.New(Nothing, New UserTablesServiceContext(), New AccountMembershipService())
- End Sub
-
- <CLSCompliant(False)> _
- Public Sub New(ByVal cloudQueueClient As CloudQueueClient, ByVal pushUserEndpointsRepository As IPushUserEndpointsRepository, ByVal membershipService As IMembershipService)
- If GetStorageAccountFromConfigurationSetting() Is Nothing Then
- If cloudQueueClient Is Nothing Then
- Throw New ArgumentNullException("cloudQueueClient", "Cloud Queue Client cannot be null if no configuration is loaded.")
- End If
- End If
-
- Me.cloudQueueClient = If(cloudQueueClient, GetStorageAccountFromConfigurationSetting().CreateCloudQueueClient())
- Me.membershipService = membershipService
- Me.pushUserEndpointsRepository = pushUserEndpointsRepository
- End Sub
-
- Public Function Microsoft() As ActionResult
- Dim users = Me.pushUserEndpointsRepository.GetAllPushUsers().Select(Function(userId) New UserModel With {.UserId = userId, .UserName = Me.membershipService.GetUserByProviderUserKey(New Guid(userId)).UserName})
-
- Return Me.View(users)
- End Function
- #End If
-
- Public Function Apple() As ActionResult
- Return Me.View()
- End Function
-
- <HttpPost()> _
- Public Function SendMicrosoftToast(ByVal userId As String, ByVal message As String) As ActionResult
- If String.IsNullOrWhiteSpace(message) Then
- Return Me.Json("The notification message cannot be null, empty nor white space.", JsonRequestBehavior.AllowGet)
- End If
-
- Dim resultList = New List(Of MessageSendResultLight)()
- Dim pushUserEndpoint = Me.pushUserEndpointsRepository.GetPushUsersByName(userId).FirstOrDefault()
- Dim uris = Me.pushUserEndpointsRepository.GetPushUsersByName(userId).Select(Function(u) u.ChannelUri)
- Dim toast = New ToastPushNotificationMessage With {.SendPriority = MessageSendPriority.High, .Title = message}
-
- For Each uri In uris
- Dim messageResult = toast.SendAndHandleErrors(New Uri(uri))
- resultList.Add(messageResult)
- If messageResult.Status.Equals(MessageSendResultLight.Success) Then
- Me.QueueMessage(pushUserEndpoint, message)
- End If
- Next uri
-
- Return Me.Json(resultList, JsonRequestBehavior.AllowGet)
- End Function
-
- <HttpPost()> _
- Public Function SendMicrosoftTile(ByVal userId As String, ByVal message As String) As ActionResult
- If String.IsNullOrWhiteSpace(message) Then
- Return Me.Json("The notification message cannot be null, empty nor white space.", JsonRequestBehavior.AllowGet)
- End If
-
- Dim resultList = New List(Of MessageSendResultLight)()
- Dim pushUserEndpointList = Me.pushUserEndpointsRepository.GetPushUsersByName(userId)
- For Each pushUserEndpoint In pushUserEndpointList
- pushUserEndpoint.TileCount += 1
- Dim tile = New TilePushNotificationMessage With {.SendPriority = MessageSendPriority.High, .Count = pushUserEndpoint.TileCount}
-
- Dim messageResult = tile.SendAndHandleErrors(New Uri(pushUserEndpoint.ChannelUri))
- resultList.Add(messageResult)
- If messageResult.Status.Equals(MessageSendResultLight.Success) Then
- Me.QueueMessage(pushUserEndpoint, message)
-
- Me.pushUserEndpointsRepository.UpdatePushUserEndpoint(pushUserEndpoint)
- End If
- Next pushUserEndpoint
-
- Return Me.Json(resultList, JsonRequestBehavior.AllowGet)
- End Function
-
- <HttpPost()> _
- Public Function SendMicrosoftRaw(ByVal userId As String, ByVal message As String) As ActionResult
- If String.IsNullOrWhiteSpace(message) Then
- Return Me.Json("The notification message cannot be null, empty nor white space.", JsonRequestBehavior.AllowGet)
- End If
-
- Dim resultList = New List(Of MessageSendResultLight)()
- Dim uris = Me.pushUserEndpointsRepository.GetPushUsersByName(userId).Select(Function(u) u.ChannelUri)
- Dim raw = New RawPushNotificationMessage With {.SendPriority = MessageSendPriority.High, .RawData = Encoding.UTF8.GetBytes(message)}
-
- For Each uri In uris
- resultList.Add(raw.SendAndHandleErrors(New Uri(uri)))
- Next uri
-
- Return Me.Json(resultList, JsonRequestBehavior.AllowGet)
- End Function
-
- <HttpPost()> _
- Public Function SendAppleMessage(ByVal deviceId As String, ByVal message As String) As ActionResult
- If String.IsNullOrWhiteSpace(deviceId) Then
- Return Me.Json("The deviceId cannot be null, empty nor white space.", JsonRequestBehavior.AllowGet)
- End If
-
- If String.IsNullOrWhiteSpace(message) Then
- Return Me.Json("The notification message cannot be null, empty nor white space.", JsonRequestBehavior.AllowGet)
- End If
-
- ' Get the Apple Notification Service settings.
- Dim thumprint = ConfigReader.GetConfigValue("AppleNotificationService.Thumbprint")
- Dim host = ConfigReader.GetConfigValue("AppleNotificationService.Host")
- Dim port = 0
- If Not Integer.TryParse(ConfigReader.GetConfigValue("AppleNotificationService.Port"), NumberStyles.Integer, CultureInfo.InvariantCulture, port) Then
- port = DefaultPort
- End If
-
- Dim certCollection As X509Certificate2Collection = Nothing
- Try
- ' Load the Apple Notification Service certificate from the store.
- Dim clientCert = CertificateUtil.GetCertificate(StoreName.My, StoreLocation.LocalMachine, thumprint)
- certCollection = New X509Certificate2Collection(clientCert)
- Catch exception As Exception
- Dim errorMessage = String.Format(CultureInfo.InvariantCulture, "Error getting the X509 certificate from the store: {0}", exception.Message)
- Return Me.Json(errorMessage, JsonRequestBehavior.AllowGet)
- End Try
-
- Dim client As TcpClient = Nothing
- Try
- ' Open connection and connect.
- client = New TcpClient(host, port)
- Dim sslStream = New SslStream(client.GetStream(), False)
-
- sslStream.AuthenticateAsClient(host, certCollection, SslProtocols.Tls, False)
-
- Dim array() As Byte = Nothing
- Using memoryStream = New MemoryStream()
- Dim writer = New BinaryWriter(memoryStream)
-
- ' Construct the message.
- writer.Write(CByte(0)) ' Command
- writer.Write(CByte(0)) ' First byte of device ID length
- writer.Write(CByte(32)) ' Device id length
-
- ' Convert to hex and write to message.
- Dim deviceToken(deviceId.Length \ 2 - 1) As Byte
- For i As Integer = 0 To deviceToken.Length - 1
- deviceToken(i) = Byte.Parse(deviceId.Substring(i * 2, 2), NumberStyles.HexNumber)
- Next i
-
- writer.Write(deviceToken)
-
- ' Construct payload within JSON message framework.
- Dim payload = String.Format(CultureInfo.InvariantCulture, "{{""aps"":{{""alert"":""{0}"",""badge"":1}}}}", message)
-
- ' Write payload data.
- writer.Write(CByte(0)) ' First byte of payload length
- writer.Write(CByte(payload.Length)) ' Actual payload length
- Dim b1() As Byte = Encoding.UTF8.GetBytes(payload)
- writer.Write(b1)
- writer.Flush()
-
- array = memoryStream.ToArray()
- End Using
-
- ' Send across the wire.
- sslStream.Write(array)
- sslStream.Flush()
- Catch exception As AuthenticationException
- Dim errorMessage = String.Format(CultureInfo.InvariantCulture, "Error authenticating against APN: {0}", exception.Message)
- Return Me.Json(errorMessage, JsonRequestBehavior.AllowGet)
- Catch exception As Exception
- Dim errorMessage = String.Format(CultureInfo.InvariantCulture, "There was an error sending the notification message: {0}", exception.Message)
- Return Me.Json(errorMessage, JsonRequestBehavior.AllowGet)
- Finally
- ' Close the client connection.
- client.Close()
- End Try
-
- ' Success.
- Return Me.Json("Success", JsonRequestBehavior.AllowGet)
- End Function
-
- Private Shared Function GetStorageAccountFromConfigurationSetting() As CloudStorageAccount
- Dim account As CloudStorageAccount = Nothing
- Try
- account = CloudStorageAccount.FromConfigurationSetting("DataConnectionString")
- Catch e1 As InvalidOperationException
- account = Nothing
- End Try
-
- Return account
- End Function
-
- Private Sub QueueMessage(ByVal pushUser As PushUserEndpoint, ByVal message As String)
- Dim queueName = GetQueueName(pushUser.PartitionKey, pushUser.RowKey, pushUser.UserId)
- Dim queue = Me.cloudQueueClient.GetQueueReference(queueName)
-
- queue.CreateIfNotExist()
- queue.AddMessage(New CloudQueueMessage(message))
- End Sub
-
- Private Shared Function GetQueueName(ByVal applicationId As String, ByVal deviceId As String, ByVal userId As String) As String
- Dim uniqueName = String.Concat(applicationId, deviceId, userId)
-
- Return String.Concat("notification", uniqueName.GetHashCode())
- End Function
- End Class
- End Namespace