예제 #1
0
        public bool SetupTransport(string serviceUri)
        {
            bool result = false;

            lock (this)
            {
                // Save these to help reconnect later.
                serverUri = serviceUri;

                // Set up the ControlChannelTrigger with the stream socket.
                result = RegisterWithControlChannelTrigger(serverUri);
                if (result == false)
                {
                    Diag.DebugPrint("Failed to sign on and connect");
                    if (socket != null)
                    {
                        socket.Dispose();
                        socket     = null;
                        readPacket = null;
                    }
                    if (channel != null)
                    {
                        channel.Dispose();
                        channel = null;
                    }
                }
            }
            return(result);
        }
예제 #2
0
        public async void SendMessage(string message)
        {
            if (socket == null)
            {
                Diag.DebugPrint("Please setup connection with the server first.");
                return;
            }
            try
            {
                if (writePacket == null)
                {
                    writePacket = new DataWriter(socket.OutputStream);
                }
                Diag.DebugPrint("Sending message to server: " + message);

                // Buffer any data we want to send.
                writePacket.UnicodeEncoding = Windows.Storage.Streams.UnicodeEncoding.Utf8;
                writePacket.WriteString(message);

                // Send the data as one complete message.
                await writePacket.StoreAsync();
            }
            catch (Exception exp)
            {
                Diag.DebugPrint("failed to write into the streamwebsocket: " + exp.Message);
            }
        }
예제 #3
0
        public bool SetupTransport(string socketUri)
        {
            bool result = false;

            lock (this)
            {
                this.socketUri = socketUri;
                result         = RegisterWithControlChannelTrigger(socketUri);

                if (result == false)
                {
                    Diag.DebugPrint("Failed to sign on and connect");

                    if (socket != null)
                    {
                        socket.Close(1001, "Failed to sign on and connect");
                        socket.Dispose();
                        socket = null;
                        reader = null;
                    }

                    if (channel != null)
                    {
                        channel.Dispose();
                        channel = null;
                    }
                }
            }

            return(result);
        }
        public bool SetupTransport(Uri serverUriIn)
        {
            bool result = false;

            lock (this)
            {
                try
                {
                    // Save these to help reconnect later.
                    serverUri = serverUriIn;

                    // Set up the CCT channel with the stream socket.
                    result = RegisterWithCCT();
                    if (result == false)
                    {
                        Diag.DebugPrint("Failed to sign on and connect");
                        DisposeProperties();
                    }
                }
                catch (Exception ex)
                {
                    Diag.DebugPrint("Failed to sign on and connect. Exception: " + ex.ToString());
                    DisposeProperties();
                }
            }
            return(result);
        }
        private void OnReadAsInputStreamCompleted(IAsyncOperationWithProgress <IInputStream, ulong> asyncInfo, AsyncStatus asyncStatus)
        {
            try
            {
                if (asyncStatus == AsyncStatus.Canceled)
                {
                    Diag.DebugPrint("IHttpContent.ReadAsInputStreamAsync was canceled.");
                    return;
                }

                if (asyncStatus == AsyncStatus.Error)
                {
                    Diag.DebugPrint("IHttpContent.ReadAsInputStreamAsync failed: " + asyncInfo.ErrorCode);
                    return;
                }

                Diag.DebugPrint("IHttpContent.ReadAsInputStreamAsync succeeded.");

                inputStream = asyncInfo.GetResults();
                ReadMore();
            }
            catch (Exception ex)
            {
                Diag.DebugPrint("Error in OnReadAsInputStreamCompleted: " + ex.ToString());
            }
        }
        public string ReadResponse(Task <HttpResponseMessage> httpResponseTask)
        {
            string message = null;

            try
            {
                if (httpResponseTask.IsCanceled || httpResponseTask.IsFaulted)
                {
                    Diag.DebugPrint("Task is cancelled or has failed");
                    return(message);
                }
                // We'll wait until we got the whole response. This is the only supported
                // scenario for HttpClient for ControlChannelTrigger.
                HttpResponseMessage httpResponse = httpResponseTask.Result;
                Diag.DebugPrint("Reading from httpresponse");
                if (httpResponse == null || httpResponse.Content == null)
                {
                    Diag.DebugPrint("Cant read from httpresponse, as either httpResponse or its content is null. try to reset connection.");
                }
                else
                {
                    // This is likely being processed in the context of a background task and so
                    // synchronously read the Content's results inline so that the Toast can be shown.
                    // before we exit the Run method.
                    message = httpResponse.Content.ReadAsStringAsync().Result;
                }
            }
            catch (Exception exp)
            {
                Diag.DebugPrint("Failed to read from httpresponse with error:  " + exp.ToString());
            }
            return(message);
        }
        private void SendHttpRequest()
        {
            // Tie the transport method to the ControlChannelTrigger object to push enable it.
            // Note that if the transport's TCP connection is broken at a later point of time,
            // the ControlChannelTrigger object can be reused to plug in a new transport by
            // calling UsingTransport again.
            Diag.DebugPrint("Calling UsingTransport() ...");
            channel.UsingTransport(httpRequest);

            // Call the SendRequestAsync function to kick start the TCP connection establishment
            // process for this HTTP request.
            Diag.DebugPrint("Calling SendRequestAsync() ...");
            sendRequestOperation            = httpClient.SendRequestAsync(httpRequest, HttpCompletionOption.ResponseHeadersRead);
            sendRequestOperation.Completed += OnSendRequestCompleted;

            // Call WaitForPushEnabled API to make sure the TCP connection has been established,
            // which will mean that the OS will have allocated any hardware or software slot for this TCP connection.

            ControlChannelTriggerStatus status = channel.WaitForPushEnabled();

            Diag.DebugPrint("WaitForPushEnabled() completed with status: " + status);
            if (status != ControlChannelTriggerStatus.HardwareSlotAllocated &&
                status != ControlChannelTriggerStatus.SoftwareSlotAllocated)
            {
                throw new Exception("Hardware/Software slot not allocated");
            }

            Diag.DebugPrint("Transport is ready to read response from server.");
        }
예제 #8
0
        async void ClientInit()
        {
            commModule = new CommModule();

            if (lockScreenAdded == false)
            {
                BackgroundAccessStatus status = await BackgroundExecutionManager.RequestAccessAsync();

                Diag.DebugPrint("Lock screen status " + status);

                switch (status)
                {
                case BackgroundAccessStatus.AlwaysAllowed:
                case BackgroundAccessStatus.AllowedSubjectToSystemPolicy:
                    lockScreenAdded = true;
                    break;

                case BackgroundAccessStatus.DeniedBySystemPolicy:
                case BackgroundAccessStatus.DeniedByUser:
                    Diag.DebugPrint("As lockscreen status was Denied, app should switch to polling mode such as email based on time triggers");
                    break;
                }
            }

            btnConnection.Visibility = Visibility.Visible;
            return;
        }
예제 #9
0
        public void OnDataReadCompletion(uint bytesRead, DataReader readPacket)
        {
            Diag.DebugPrint("OnDataReadCompletion Entry");
            if (readPacket == null)
            {
                Diag.DebugPrint("DataReader is null");
                return;
            }

            uint buffLen = readPacket.UnconsumedBufferLength;

            Diag.DebugPrint($"bytesRead: {bytesRead}, unconsumedBufferLength: {buffLen}");

            if (buffLen == 0)
            {
                Diag.DebugPrint("Received zero bytes from the socket. Server must have closed the connection.");
                Diag.DebugPrint("Try disconnecting and reconnecting to the server");
                return;
            }

            string serializedMessage = readPacket.ReadString(buffLen);
            var    message           = JsonConvert.DeserializeObject <Message>(serializedMessage);

            Diag.DebugPrint("Received Buffer: " + serializedMessage);

            actions.ReceiveMessage(message);

            AppContext.Enqueue(message);

            PostSocketRead(MAX_BUFFER_LENGTH);
            Diag.DebugPrint("OnDataReadCompletion Exit");
        }
예제 #10
0
        public static async Task AcceptConnection(string serviceName, CommModule myCommModule)
        {
            // Create and store a streamsocketlistener in the class. This way, new connections
            // can be automatically accepted.
            if (myCommModule.serverListener == null)
            {
                myCommModule.serverListener = new StreamSocketListener();
            }

            myCommModule.serverListener.ConnectionReceived += (op, evt) =>
            {
                // For simplicity, the server can talk to only one client at a time.
                myCommModule.serverSocket = evt.Socket;
                if (myCommModule.writePacket != null)
                {
                    myCommModule.writePacket.DetachStream();
                    myCommModule.writePacket = null;
                }

                Diag.DebugPrint("Connection Received!");
            };
            await myCommModule.serverListener.BindServiceNameAsync(serviceName);

            return;
        }
예제 #11
0
        // Registers a background task with an network change system trigger.
        private void RegisterNetworkChangeTask()
        {
            try
            {
                if (NetworkTaskRegistrationGuid != Guid.Empty)
                {
                    IReadOnlyDictionary <Guid, IBackgroundTaskRegistration> allTasks = BackgroundTaskRegistration.AllTasks;
                    if (allTasks.ContainsKey(NetworkTaskRegistrationGuid))
                    {
                        Diag.DebugPrint("Network task is already registered.");
                        return;
                    }
                }

                BackgroundTaskBuilder myTaskBuilder = new BackgroundTaskBuilder();
                SystemTrigger         myTrigger     = new SystemTrigger(SystemTriggerType.NetworkStateChange, false);
                myTaskBuilder.SetTrigger(myTrigger);
                myTaskBuilder.TaskEntryPoint = "Background.NetworkChangeTask";
                myTaskBuilder.Name           = "Network change task";
                BackgroundTaskRegistration myTask = myTaskBuilder.Register();
                NetworkTaskRegistrationGuid = myTask.TaskId;
            }
            catch (Exception exp)
            {
                Diag.DebugPrint("Exception caught while setting up system event" + exp.ToString());
            }
        }
        private void SetUpHttpRequestAndSendToHttpServer()
        {
            try
            {
                AppendOriginToUri();

                Diag.DebugPrint("SetUpHttpRequestAndSendToHttpServer started with URI: " + serverUri);

                // IMPORTANT:
                // For HTTP based transports that use ControlChannelTrigger, whenever we send the next request,
                // we will abort the earlier outstanding HTTP request and start a new one.
                // For example, when the HTTP server is taking longer to reply, and the keep alive trigger is fired
                // in-between then the keep alive task will abort the outstanding HTTP request and start a new request
                // which should be finished before the next keep alive task is triggered.
                ResetRequest();

                httpRequest = new HttpRequestMessage(HttpMethod.Get, serverUri);

                SendHttpRequest();
            }
            catch (Exception ex)
            {
                Diag.DebugPrint("Connect failed with: " + ex.ToString());
                throw;
            }
        }
        private async void ListenButton_Click(object sender, RoutedEventArgs e)
        {
            if (listenState == listeningStates.notListening)
            {
                string serverPort = GetServerPort();

                bool result = await Task <bool> .Factory.StartNew(() =>
                {
                    return(commModule.SetupTransport(null, serverPort));
                });

                Diag.DebugPrint("CommModule setup result: " + result);
                if (result == true)
                {
                    ListenButton.Content = "Stop Listening";
                    listenState          = listeningStates.listening;
                }
                else
                {
                    ListenButton.Content = "failed to listen. click to retry";
                    listenState          = listeningStates.notListening;
                }
            }
            else
            {
                await ResetTransportTaskAsync();

                listenState          = listeningStates.notListening;
                ListenButton.Content = "Listen";
            }
        }
예제 #14
0
        // Registers a background task with a network change system trigger.
        private void RegisterNetworkChangeTask()
        {
            try
            {
                // Delete previously registered network status change tasks as
                // the background triggers are persistent by nature across process
                // lifetimes.
                foreach (var cur in BackgroundTaskRegistration.AllTasks)
                {
                    Diag.DebugPrint("Deleting Background Taks " + cur.Value.Name);
                    cur.Value.Unregister(true);
                }

                var myTaskBuilder = new BackgroundTaskBuilder();
                var myTrigger     = new SystemTrigger(SystemTriggerType.NetworkStateChange, false);
                myTaskBuilder.SetTrigger(myTrigger);
                myTaskBuilder.TaskEntryPoint = "Background.NetworkChangeTask";
                myTaskBuilder.Name           = "Network change task";
                var myTask = myTaskBuilder.Register();
            }
            catch (Exception exp)
            {
                Diag.DebugPrint("Exception caught while setting up system event" + exp.ToString());
            }
        }
예제 #15
0
 private void ClientRole_Click(object sender, RoutedEventArgs e)
 {
     // To keep things simple, this button is disabled once clicked.
     Diag.DebugPrint("Client role selected");
     ClientRoleButton.IsEnabled = false;
     ClientInit();
 }
        private void OnSendRequestCompleted(IAsyncOperationWithProgress <HttpResponseMessage, HttpProgress> asyncInfo, AsyncStatus asyncStatus)
        {
            try
            {
                if (asyncStatus == AsyncStatus.Canceled)
                {
                    Diag.DebugPrint("HttpRequestMessage.SendRequestAsync was canceled.");
                    return;
                }

                if (asyncStatus == AsyncStatus.Error)
                {
                    Diag.DebugPrint("HttpRequestMessage.SendRequestAsync failed: " + asyncInfo.ErrorCode);
                    return;
                }

                Diag.DebugPrint("HttpRequestMessage.SendRequestAsync succeeded.");

                HttpResponseMessage response = asyncInfo.GetResults();
                readAsInputStreamOperation           = response.Content.ReadAsInputStreamAsync();
                readAsInputStreamOperation.Completed = OnReadAsInputStreamCompleted;
            }
            catch (Exception ex)
            {
                Diag.DebugPrint("Error in OnSendRequestCompleted: " + ex.ToString());
            }
        }
        private void SetupHttpRequestAndSendToHttpServer()
        {
            try
            {
                Diag.DebugPrint("SetupHttpRequestAndSendToHttpServer started with uri: " + serverUri);

                // IMPORTANT:
                // For HTTP based transports that use the RTC broker, whenever we send next request, we will abort the earlier
                // outstanding http request and start new one.
                // For example in case when http server is taking longer to reply, and keep alive trigger is fired in-between
                // then keep alive task will abort outstanding http request and start a new request which should be finished
                // before next keep alive task is triggered.
                if (httpRequest != null)
                {
                    httpRequest.Dispose();
                }

                httpRequest = RtcRequestFactory.Create(HttpMethod.Get, serverUri);

                SendHttpRequest();
            }
            catch (Exception e)
            {
                Diag.DebugPrint("Connect failed with: " + e.ToString());
                throw;
            }
        }
예제 #18
0
 private void ShowBackgroundTasks(object sender, RoutedEventArgs e)
 {
     Diag.DebugPrint("Background Tasks: ");
     foreach (var cur in BackgroundTaskRegistration.AllTasks)
     {
         Diag.DebugPrint($"    {cur.Value.Name}");
     }
 }
예제 #19
0
 private void TestSocket(object sender, RoutedEventArgs e)
 {
     if (!(string.IsNullOrEmpty(txtMessage.Text)))
     {
         Diag.DebugPrint("TestSocket: Posting message to Web API and returning a notification");
         SendMessage(txtMessage.Text);
     }
 }
예제 #20
0
 void UnregisterBackgroundTasks()
 {
     foreach (var cur in BackgroundTaskRegistration.AllTasks)
     {
         Diag.DebugPrint("Deleting Background Task " + cur.Value.Name);
         cur.Value.Unregister(true);
     }
 }
예제 #21
0
        public void Run(Windows.ApplicationModel.Background.IBackgroundTaskInstance taskInstance)
        {
            if (taskInstance == null)
            {
                Diag.DebugPrint("PushNotifyTask: taskInstance was null");
                return;
            }

            Diag.DebugPrint("PushNotifyTask " + taskInstance.Task.Name + " Starting...");

            // Use the ControlChannelTriggerEventDetails object to derive the context for this background task.
            // The context happens to be the channelId that apps can use to differentiate between
            // various instances of the channel..
            var channelEventArgs = taskInstance.TriggerDetails as IControlChannelTriggerEventDetails;

            ControlChannelTrigger channel = channelEventArgs.ControlChannelTrigger;

            if (channel == null)
            {
                Diag.DebugPrint("Channel object may have been deleted.");
                return;
            }

            string channelId = channel.ControlChannelTriggerId;

            if (((IDictionary <string, object>)CoreApplication.Properties).ContainsKey(channelId))
            {
                try
                {
                    string messageReceived = "PushNotification Received";
                    var    appContext      = ((IDictionary <string, object>)CoreApplication.Properties)[channelId] as AppContext;

                    // Process any messages that have been enqueued by the receive completion handler.
                    bool result = AppContext.messageQueue.TryDequeue(out messageReceived);
                    if (result)
                    {
                        Diag.DebugPrint("Message: " + messageReceived);
                        InvokeSimpleToast(messageReceived);
                    }
                    else
                    {
                        Diag.DebugPrint("There was no message for this push notification: ");
                    }
                }
                catch (Exception exp)
                {
                    Diag.DebugPrint("PushNotifyTask failed with: " + exp.Message);
                }
            }
            else
            {
                Diag.DebugPrint("Cannot find AppContext key " + channelId);
            }

            Diag.DebugPrint("PushNotifyTask " + taskInstance.Task.Name + " finished.");
        }
예제 #22
0
        private void ClientRole_Click(object sender, RoutedEventArgs e)
        {
            Diag.DebugPrint("Client role selected");

            // In order to simplify the sample and focus on the core controlchanneltrigger
            // related concepts, once a role is selected, the app has
            // to be restarted to change the role.
            ClientRoleButton.IsEnabled = false;
            ClientInit();
        }
예제 #23
0
        public void Run(IBackgroundTaskInstance taskInstance)
        {
            if (taskInstance == null)
            {
                Diag.DebugPrint("NetworkChangeTask: taskInstance was null");
                return;
            }

            NetworkStateChangeEventDetails details = taskInstance.TriggerDetails as NetworkStateChangeEventDetails;

            // Only restart CCT connection if network connectivity level changes.
            if (details.HasNewNetworkConnectivityLevel == false)
            {
                return;
            }

            Diag.DebugPrint("System task - " + taskInstance.Task.Name + " starting ...");

            // In this example, the channel name has been hardcoded to lookup the property bag
            // for any previous contexts. The channel name may be used in more sophisticated ways
            // in case an app has multiple ControlChannelTrigger objects.
            string channelId = "channelOne";

            if (((IDictionary <string, object>)CoreApplication.Properties).ContainsKey(channelId))
            {
                try
                {
                    AppContext appContext = null;
                    lock (CoreApplication.Properties)
                    {
                        appContext = ((IDictionary <string, object>)CoreApplication.Properties)[channelId] as AppContext;
                    }
                    if (appContext != null && appContext.CommunicationInstance != null)
                    {
                        CommunicationModule communicationInstance = appContext.CommunicationInstance;

                        // Clear any existing channels, sockets etc.
                        communicationInstance.Reset();

                        // Create CCT enabled transport.
                        communicationInstance.SetUpTransport(communicationInstance.serverUri, GetType().Name);
                    }
                }
                catch (Exception ex)
                {
                    Diag.DebugPrint("Registering with CCT failed with: " + ex.ToString());
                }
            }
            else
            {
                Diag.DebugPrint("Cannot find AppContext key channelOne");
            }

            Diag.DebugPrint("System task - " + taskInstance.Task.Name + " finished.");
        }
예제 #24
0
 private void CheckEnter(object sender, KeyRoutedEventArgs e)
 {
     if (e.Key == Windows.System.VirtualKey.Enter)
     {
         if (!(string.IsNullOrEmpty(txtMessage.Text)))
         {
             Diag.DebugPrint("TestSocket: Posting message to Web API and returning a notification");
             SendMessage(txtMessage.Text);
         }
     }
 }
예제 #25
0
        void PostSocketRead(int length)
        {
            Diag.DebugPrint("Entering PostSocketRead");
            // IMPORTANT: When using winRT based transports such as StreamSocket with the ControlChannelTrigger,
            // we have to use the raw async pattern for handling reads instead of the await model.
            // Using the raw async pattern allows Windows to synchronize the PushNotification task's
            // IBackgroundTask::Run method with the return of the receive  completion callback.
            // The Run method is invoked after the completion callback returns. This ensures that the app has
            // received the data/errors before the Run method is invoked.
            // It is important to note that the app has to post another read before it returns control from the completion callback.
            // It is also important to note that the DataReader is not directly used with the
            // StreamSocket transport since that breaks the synchronization described above.
            // It is not supported to use DataReader's LoadAsync method directly on top of the transport. Instead,
            // the IBuffer returned by the transport's ReadAsync method can be later passed to DataReader::FromBuffer()
            // for further processing.
            try
            {
                var readBuf = new Windows.Storage.Streams.Buffer((uint)length);
                var readOp  = socket.InputStream.ReadAsync(readBuf, (uint)length, InputStreamOptions.Partial);
                readOp.Completed = (IAsyncOperationWithProgress <IBuffer, uint> asyncAction, AsyncStatus asyncStatus) =>
                {
                    switch (asyncStatus)
                    {
                    case AsyncStatus.Completed:
                    case AsyncStatus.Error:
                        try
                        {
                            // GetResults in AsyncStatus::Error is called as it throws a user friendly error string.
                            IBuffer localBuf  = asyncAction.GetResults();
                            uint    bytesRead = localBuf.Length;
                            readPacket = DataReader.FromBuffer(localBuf);
                            OnDataReadCompletion(bytesRead, readPacket);
                        }
                        catch (Exception exp)
                        {
                            Diag.DebugPrint("Read operation failed:  " + exp.Message);
                        }
                        break;

                    case AsyncStatus.Canceled:

                        // Read is not cancelled in this sample.
                        break;
                    }
                };
            }
            catch (Exception exp)
            {
                Diag.DebugPrint("failed to post a read failed with error:  " + exp.Message);
            }
            Diag.DebugPrint("Leaving PostSocketRead");
        }
 public bool SendMessageToHttpServer()
 {
     try
     {
         SetupHttpRequestAndSendToHttpServer();
         return(true);
     }
     catch (Exception ex)
     {
         Diag.DebugPrint("httpClient write failed with error:  " + ex.ToString());
         return(false);
     }
 }
예제 #27
0
        async Task SendNotification(Notification notification)
        {
            using (var client = new HttpClient())
            {
                var message = new HttpRequestMessage(HttpMethod.Post, new Uri(sendUri));
                message.Headers.Accept.Add(new HttpMediaTypeWithQualityHeaderValue("application/json"));
                var content = new HttpStringContent(JsonConvert.SerializeObject(notification), UnicodeEncoding.Utf8, "application/json");
                message.Content = content;
                var result = await client.SendRequestAsync(message);

                Diag.DebugPrint($"SendNotification: Completed with status code {result.StatusCode}: {result.ReasonPhrase}");
            }
        }
 public static Uri CreateSocketServerUri(this string socketUri)
 {
     try
     {
         var serverSocket = new Uri(socketUri);
         return(serverSocket);
     }
     catch (Exception ex)
     {
         Diag.DebugPrint("Error creating URI: " + ex.Message);
         return(null);
     }
 }
예제 #29
0
        public void Reset()
        {
            lock (this)
            {
                if (readPacket != null)
                {
                    try
                    {
                        readPacket.DetachStream();
                        readPacket = null;
                    }
                    catch (Exception exp)
                    {
                        Diag.DebugPrint("Could not detach DataReader: " + exp.Message);
                    }
                }

                if (writePacket != null)
                {
                    try
                    {
                        writePacket.DetachStream();
                        writePacket = null;
                    }
                    catch (Exception exp)
                    {
                        Diag.DebugPrint("Could not detach DataWriter: " + exp.Message);
                    }
                }

                if (socket != null)
                {
                    socket.Dispose();
                    socket = null;
                }

                if (channel != null)
                {
                    if (((IDictionary <string, object>)CoreApplication.Properties).ContainsKey(channel.ControlChannelTriggerId))
                    {
                        CoreApplication.Properties.Remove(channel.ControlChannelTriggerId);
                    }

                    // Call the Dispose() method on the controlchanneltrigger object to release any
                    // OS maintained resources for this channel object.
                    channel.Dispose();
                    channel = null;
                }
                Diag.DebugPrint("CommModule has been reset.");
            }
        }
예제 #30
0
        protected override async void OnBackgroundActivated(BackgroundActivatedEventArgs e)
        {
            base.OnBackgroundActivated(e);

            var deferral = e.TaskInstance.GetDeferral();

            switch (e.TaskInstance.Task.Name)
            {
            case "ToastTask":
                try
                {
                    Diag.DebugPrint("ToastTask Starting...");

                    e.TaskInstance.Canceled += new BackgroundTaskCanceledEventHandler((sender, reason) =>
                    {
                        deferral.Complete();
                    });

                    var details = e.TaskInstance.TriggerDetails as ToastNotificationActionTriggerDetail;

                    if (details != null)
                    {
                        var args = QueryString.Parse(details.Argument);

                        if (args["uri"] != null)
                        {
                            Diag.DebugPrint("ToastTask: Launching URI - " + args["uri"]);
                            await Windows.System.Launcher.LaunchUriAsync(new Uri(args["uri"]));
                        }
                        else
                        {
                            Diag.DebugPrint("ToastTask: No launch URI found for this toast");
                        }
                    }
                    else
                    {
                        Diag.DebugPrint("ToastTask: No Trigger Details found for this task");
                    }
                }
                catch (Exception ex)
                {
                    Diag.DebugPrint("ToastTask failed with: " + ex.Message);
                }
                break;

            default:
                break;
            }

            deferral.Complete();
        }