WNS PushNotificationReceived does not intercept toast push notification - c#

I'm writing a windows desktop app that relies on notifications to work. However, the event handler code, PushNotificationReceived on the channel does not seem to actually fire when I receive a notification. The following code is called to get the channel before its uri is sent to my server:
internal async Task<PushNotificationChannel> GetChannel()
{
PushNotificationChannel pnc;
try
{
pnc = await PushNotificationChannelManager.CreatePushNotificationChannelForApplicationAsync();
if (_channel == null || !pnc.Uri.Equals(_channel.Uri))
{
_channel = pnc;
_channel.PushNotificationReceived += OnPushNotificationReceived;
Debug.WriteLine(_channel.Uri);
}
}
catch (Exception ex)
{
Debug.WriteLine(ex.Message);
_channel = null;
}
dispatcher = Windows.UI.Core.CoreWindow.GetForCurrentThread().Dispatcher;
return _channel;
}
Such that anytime the channel is created or updated (via a different channel uri), it should assign the new channel's PushNotificationReceived event to the following (which is basically lifted from msdn's example):
void OnPushNotificationReceived(PushNotificationChannel sender, PushNotificationReceivedEventArgs e)
{
string typeString = String.Empty;
string notificationContent = String.Empty;
switch (e.NotificationType)
{
//
//other notification types omitted for brevity
//
case PushNotificationType.Toast:
notificationContent = e.ToastNotification.Content.GetXml();
typeString = "Toast";
// Setting the cancel property prevents the notification from being delivered. It's especially important to do this for toasts:
// if your application is already on the screen, there's no need to display a toast from push notifications.
e.Cancel = true;
break;
}
Debug.WriteLine("Received notification, with payload: {0}", notificationContent);
string text = "Received a " + typeString + " notification, containing: " + notificationContent;
var ignored = dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
{
MainPage.Current.ClearBanner();
});
}
Importantly, "MainPage.Current" is a reference to the app's main page as a static variable. The clear banner line simply removes a pink banner from the main page (just trying to get something simple working to start).
However, the code never seems to fire (no debug statement, pink banner remains). I am successfully getting the toast notification, and clicking on it will set focus to my app, so it's definitely not going to the wrong place.
Is there something I am doing wrong or some way to debug the notifications themselves?

Related

FCM Background Notification on IOS app in Xamarin C# not working

The team is developing an IOS app on Xamarin in c# . Now we wanted to use the push notification service of fcm . Tried deploying the app but the issue is : The notifications are not received on ios if the app is in background. Did some research on it but found that the app disconnects from fcm when goes in background. Although tried not to disconnect it by not invoking the function but still the notifications were not received. Just wanted to know whether it's possible to receive the notification on ios while the app is in the background.
Sharing the relevant link and also the code for background that disconnects the app from fcm when it goes in background. Also removed the function call but it did not work.
public override void DidEnterBackground (UIApplication application)
{
// Use this method to release shared resources, save user data,
//invalidate timers and store the application state.
// If your application supports background exection this method is
//called instead of WillTerminate when the user quits.
Messaging.SharedInstance.Disconnect ();
Console.WriteLine (“Disconnected from FCM”);
}
Link:
https://components.xamarin.com/gettingstarted/firebaseioscloudmessaging/true
public override bool FinishedLaunching(UIApplication application, NSDictionary launchOptions)
{
App.Configure ();
// Register your app for remote notifications.
if (UIDevice.CurrentDevice.CheckSystemVersion (10, 0)) {
// For iOS 10 display notification (sent via APNS)
UNUserNotificationCenter.Current.Delegate = this;
var authOptions = UNAuthorizationOptions.Alert | UNAuthorizationOptions.Badge | UNAuthorizationOptions.Sound;
UNUserNotificationCenter.Current.RequestAuthorization (authOptions, (granted, error) => {
Console.WriteLine (granted);
});
} else {
// iOS 9 or before
var allNotificationTypes = UIUserNotificationType.Alert | UIUserNotificationType.Badge | UIUserNotificationType.Sound;
var settings = UIUserNotificationSettings.GetSettingsForTypes (allNotificationTypes, null);
UIApplication.SharedApplication.RegisterUserNotificationSettings (settings);
}
UIApplication.SharedApplication.RegisterForRemoteNotifications ();
Messaging.SharedInstance.Delegate = this;
// To connect with FCM. FCM manages the connection, closing it
// when your app goes into the background and reopening it
// whenever the app is foregrounded.
Messaging.SharedInstance.ShouldEstablishDirectChannel = true;
return true;
}
Next put this in the AppDelegate.cs
[Export("messaging:didReceiveRegistrationToken:")]
public void DidReceiveRegistrationToken(Messaging messaging, string fcmToken)
{
// Monitor token generation: To be notified whenever the token is updated.
LogInformation(nameof(DidReceiveRegistrationToken), $"Firebase registration token: {fcmToken}");
// TODO: If necessary send token to application server.
// Note: This callback is fired at each app startup and whenever a new token is generated.
}
// You'll need this method if you set "FirebaseAppDelegateProxyEnabled": NO in GoogleService-Info.plist
//public override void RegisteredForRemoteNotifications (UIApplication application, NSData deviceToken)
//{
// Messaging.SharedInstance.ApnsToken = deviceToken;
//}
public override void DidReceiveRemoteNotification(UIApplication application, NSDictionary userInfo, Action<UIBackgroundFetchResult> completionHandler)
{
// Handle Notification messages in the background and foreground.
// Handle Data messages for iOS 9 and below.
// If you are receiving a notification message while your app is in the background,
// this callback will not be fired till the user taps on the notification launching the application.
// TODO: Handle data of notification
// With swizzling disabled you must let Messaging know about the message, for Analytics
//Messaging.SharedInstance.AppDidReceiveMessage (userInfo);
if(ConnectionClass.CompanyID != null)
{
SyncData.SyncDataDB();
}
//FirebasePushNotificationManager.CurrentNotificationPresentationOption = UNNotificationPresentationOptions.Alert;
FirebasePushNotificationManager.DidReceiveMessage(userInfo);
//HandleMessage(userInfo);
// Print full message.
//LogInformation(nameof(DidReceiveRemoteNotification), userInfo);
//completionHandler(UIBackgroundFetchResult.NewData);
}
[Export("messaging:didReceiveMessage:")]
public void DidReceiveMessage(Messaging messaging, RemoteMessage remoteMessage)
{
// Handle Data messages for iOS 10 and above.
HandleMessage(remoteMessage.AppData);
LogInformation(nameof(DidReceiveMessage), remoteMessage.AppData);
}
void HandleMessage(NSDictionary message)
{
if (MessageReceived == null)
return;
MessageType messageType;
if (message.ContainsKey(new NSString("aps")))
messageType = MessageType.Notification;
else
messageType = MessageType.Data;
var e = new UserInfoEventArgs(message, messageType);
MessageReceived(this, e);
}
public static void ShowMessage(string title, string message, UIViewController fromViewController, Action actionForOk = null)
{
if (UIDevice.CurrentDevice.CheckSystemVersion(8, 0))
{
var alert = UIAlertController.Create(title, message, UIAlertControllerStyle.Alert);
alert.AddAction(UIAlertAction.Create("Ok", UIAlertActionStyle.Default, (obj) => actionForOk?.Invoke()));
fromViewController.PresentViewController(alert, true, null);
}
else
{
var alert = new UIAlertView(title, message, null, "Ok", null);
alert.Clicked += (sender, e) => actionForOk?.Invoke();
alert.Show();
}
}
void LogInformation(string methodName, object information) => Console.WriteLine($"\nMethod name: {methodName}\nInformation: {information}");

Redirect to a different aspx page and run the next code in background (.NET 4.5.2)

I am working on an ASP.NET Webform project (legacy code).On my button_click event i am sending sms message to all the datas populated in this.
var customerSMS = BusinessLayer.SMS.SmsSetup.GetAllCustomerSMS(OfficeId);
This takes around 15seconds to do all the computing and get the data(1000rows)
from the Db.And for each data it runs through the loop and does validation and
sends the sms and it does take time.I want to do this task in background and
redirect the user to the index page and the background process continues till it
gets out of the loop.I am new to this and still learning this beautiful
language C#.I did go through this amazing Asynchronous Programming async/await
and Multithreading approach and got hold of it only in simple WindowsForm
applications.Any reference/code snippet/best approach with a simple explanation for my case would be helpful.
My button click event code :
protected void ReturntoDashboard_Click(object sender, EventArgs e)
{
sms = Everest.Net.BusinessLayer.SMS.SmsSetup.GetSmsSetUp(OfficeId);
if (sms.EnableSmsData && sms.SmsCount > 0)
{
#region Loan Section
var smsLoan = Everest.Net.BusinessLayer.SMS.SmsSetup.GetLoanId(s.Sms_AccountNumber);
var loanId =
BusinessLayer.SMS.SmsSetup.GetLoanIdValue(s.Sms_AccountNumber);
var dateexceeded =
BusinessLayer.SMS.SmsSetup.IsDateExceeded(loanId);
if (smsLoan != null && dateexceeded == true)
{
foreach (Common.SMS.SMSSetup sm in smsLoan)
{
var smsClosingBalanceLoan = BusinessLayer.SMS.SmsSetup.GetAmountForLoanAlert( sm.LoanId,
BusinessLayer.Core.DateConversion
.GetCurrentServerDate()
.AddDays(sms.DaysbeforeLoanalerts).ToString());
if (smsClosingBalanceLoan != null)
{
if (smsClosingBalanceLoan.LoanAmountToPay > 0)
{
int smsSentAlertCount = sms.LoanAlertCount;
var logCount = BusinessLayer.SMS.SmsSetup.GetLoanSmsAlertSentCount(DateTime.Now.AddDays(-smsSentAlertCount).ToString("yyyy-MM-dd"), DateTime.Now.ToString("yyyy-MM-dd"), sm.LoanAccountNumber);
if (logCount < smsSentAlertCount)
{
smsLog = new Everest.Net.Common.SMS.SMSSetup();
finalMessage = "Dear Member, Your Loan accnt " + sm.LoanAccountNumber + " with Principal"+ "+" + "Int Amnt: Rs." + smsClosingBalanceLoan.LoanAmountToPay + " need to be payed.Thank You," + officeName.OfficeName;
smsLog.LogServiceType = "Loan";
smsLog.LogSmsType = s.Sms_SmsType;
smsLog.LogSmsMessage = finalMessage;
smsLog.LogCustomerId = s.CustomerId.ToString();
smsLog.LogAccountNumber = s.Sms_AccountNumber;
smsLog.LogAccountType = s.Sms_AccountType;
smsLog.LogSmsSentDate = BusinessLayer.Core.DateConversion.GetCurrentServerDate();
smsLog.LogSmsFailedDate = "";
smsLog.LogSentStatus = true;
smsLog.LogUserId = UserId;
smsLog.LogSmsFailedMessage = "";
try
{
var result = Everest.Net.BusinessLayer.SMS.smsParameters.SendSMS(sms.FromNum, sms.Token, sms.Url, cellNum, finalMessage);
}
catch (Exception ex)
{
smsLog.LogSmsFailedDate = System.DateTime.Now.ToString("MM/dd/yyyy HHmmss");
smsLog.LogSentStatus = false;
smsLog.LogSmsFailedMessage = ex.Message;
Everest.Net.BusinessLayer.SMS.SmsSetup.InsertSMSLog(smsLog);
}
sms = Everest.Net.BusinessLayer.SMS.SmsSetup.GetSmsSetUp(OfficeId);
sms.SmsCount = sms.SmsCount - 1;
Everest.Net.BusinessLayer.SMS.SmsSetup.UpdateSmsSetup(sms);
Everest.Net.BusinessLayer.SMS.SmsSetup.InsertSMSLog(smsLog);
}
}
}
}
}
}
}
}
catch (Exception ex)
The ideal solution would remove the responsibility of sending the SMS from the web application itself. Instead, the web application should create a database record containing the message and recipient addresses, and a separate background job (e.g. a Windows Service) should poll the database and send SMS messages when neeeded. This is the best solution in terms of fault tolerance and auditability, because there is a permanent record of the messaging job which can be resumed if the system fails.
That being said, maybe you don't want to go to all that trouble. If you feel strongly that you wish to send the SMS directly from the ASP.NET application, you will need to create a Task and queue it to run using QueueBackgroundWorkitem. You will need to refactor your code a bit.
Move all the logic for sending the SMS into a separate function that accepts all the information needed as parameters. For example,
static void SendSMS(string[] addresses, string messagetext)
{
//Put your SMS code here
}
When you need to call the function, queue it as a background item
HostingEnvironment.QueueBackgroundWorkItem(a => SendSMS(addresses, messageText));
If your worker task needs to access its own cancellation token (e.g. if it is supposed to loop until cancelled), it is passed as an argument to the lambda expression. So you could modify the prototype
static void SendSMS(string[] addresses, string messagetext, CancellationToken token)
{
while (!token.IsCancellationRequested)
{
//Put your code here
}
}
and pass it thus:
HostingEnvironment.QueueBackgroundWorkItem(token => SendSMS(addresses, messageText, token));
Placing the task in the background queue ensures that ASP.NET keeps track of the thread, doesn't try to garbage collect it, and shuts it down properly when the application pool needs to shut down.
After queuing the background operation, your page can render is content per usual and conclude the HTTP response while the task continues to execute.

blocking listen prevents disconnect

Overview of Problem:
I need to connect to an IRC Server. Once connected, the program will send a message to the channel, and a response will occur over multiple lines back. I need to read these lines and store in a variable for later use. A special character at the end of the message (]) will define the end of the message over multiple lines. Once we have received this character, the IRC session should disconnect and processing should continue.
Situation:
I am using the Smartirc4net library. Calling irc.Disconnect() takes about 40 seconds to disconnect the session. Once we've received the ] character, the session should be disconnected, Listen() should not be blocking, and the rest of the program should continue to run.
Research:
I have found this: smartirc4net listens forever, can't exit thread, and I think it might be the same issue, however, I am unsure of what I need to do to resolve the problem.
Code:
public class IrcCommunicator
{
public IrcClient irc = new IrcClient();
string data;
public string Data { get { return data; } }
// this method we will use to analyse queries (also known as private messages)
public void OnQueryMessage(object sender, IrcEventArgs e)
{
data += e.Data.Message;
if (e.Data.Message.Contains("]"))
{
irc.Disconnect(); //THIS TAKES 40 SECONDS!!!
}
}
public void RunCommand()
{
irc.OnQueryMessage += new IrcEventHandler(OnQueryMessage);
string[] serverlist;
serverlist = new string[] { "127.0.0.1" };
int port = 6667;
string channel = "#test";
try
{
irc.Connect(serverlist, port);
}
catch (ConnectionException e)
{
// something went wrong, the reason will be shown
System.Console.WriteLine("couldn't connect! Reason: " + e.Message);
}
try
{
// here we logon and register our nickname and so on
irc.Login("test", "test");
// join the channel
irc.RfcJoin(channel);
irc.SendMessage(SendType.Message, "test", "!query");
// here we tell the IRC API to go into a receive mode, all events
// will be triggered by _this_ thread (main thread in this case)
// Listen() blocks by default, you can also use ListenOnce() if you
// need that does one IRC operation and then returns, so you need then
// an own loop
irc.Listen();
// when Listen() returns our IRC session is over, to be sure we call
// disconnect manually
irc.Disconnect();
}
catch (Exception e)
{
// this should not happen by just in case we handle it nicely
System.Console.WriteLine("Error occurred! Message: " + e.Message);
System.Console.WriteLine("Exception: " + e.StackTrace);
}
}
}
IrcBot bot = new IrcBot();
bot.RunCommand();
ViewBag.IRC = bot.Data;
As you can see, once this
Thank you for your time to look at this code and read my problem description. If you have any thoughts, or other suggestions, please let me know.
Mike
I was able to successfully disconnect straight away by calling RfcQuit() within OnQueryMessage(), before irc.Disconnect();

Detecting a web socket connection drop

In my Windows 8 JS application, I have a web socket object defined like this:
var webSocket = new Windows.Networking.Sockets.MessageWebSocket();
webSocket.control.messageType = Windows.Networking.Sockets.SocketMessageType.utf8;
webSocket.onmessagereceived = that._onMessageReceived;
webSocket.onclosed = that._onClosed;
I connect using webSocket.connectAsync(uri).done(/* ... */) and that part works fine.
If I stop my web server on the other end, my application doesn't get notified and thinks the connection is still alive. The 'closed' event never fires, and there doesn't seem to be any 'Error' event.
Is there a way to monitor the connection status?
Figured it out. The messagereceived event actually fires when the connection fails. Inside the handler, you can use a try catch block around the data reader operation.
try {
var dataReader = args.getDataReader();
var msg = dataReader.readString(dataReader.unconsumedBufferLength);
} catch (ex) {
var error = Windows.Networking.Sockets.SocketError.getStatus(ex.number);
// do something
}
Is this a specific Windows 8 question? I've tested the following to work on Windows 7, OSX and Ubuntu (using reasonably new versions of Firefox, Safari and Chrome):
var s = new WebSocket("ws://"+window.location.hostname+":9876");
s.onopen = function(e) {
console.log("opened socket for unidrive log");
}
s.onclose = function(e) {
console.log("closed");
}
s.onmessage = function(e) {
console.log("got message: " + e.data);
}
The onclose event fires immediately if the web-server isn't running to start with, or fires on killing the server.
Thank you for this Information - really weird why the socket don't raise the closed-event, but it works great.
One more info for C# developers: to determine the correct exception-errorstatus you have to do call the WebSocketError.GetStatus(hresult) instead of the SocketError.GetStatus(hresult) method.
try
{
using (DataReader reader = e.GetDataReader())
{
reader.UnicodeEncoding = Windows.Storage.Streams.UnicodeEncoding.Utf8;
string rawMessage = reader.ReadString(reader.UnconsumedBufferLength);
// Do something with the message...
}
}
catch (Exception ex)
{
var errorStatus = Windows.Networking.Sockets.WebSocketError.GetStatus(ex.HResult);
if (errorStatus == WebErrorStatus.ConnectionAborted)
{
// Handle the connection-abort...
}
}

Two Toast notifications for same app, at the same time. How is it prioritized and handled by the device?

I have an app which can(possibly) show two toast notifications to the user one after the other. I observed that if such scenario arises then only one of the two notifications is displayed to the user but once the user launches the app and then same notifications are presented to the user in message boxes and if he clicks "cancel" for the first message and then the next notification is presented. So, my doubt now is, If two toast notifications are there then how will the device handle it? and which of the two is displayed to the user? And in case only notification is presented to the user (by default behaviour of the device) then is there a way to display notifications one after the other?
This is similar to this QUESTION but i want to know the behaviour of WP7 phones as the features of WP7 very different other smartphone OSes.
All suggestions, comments and answers are appreciated.
Thank You
Windows Phone 7 has the potential to show both the messages, and which one first depends on which one the phone receives first.
If you look at the diagram on this page http://msdn.microsoft.com/en-us/library/windowsphone/develop/ff402558(v=vs.92).aspx you see that there is a lot of communication in sending a push (toast, tile or raw) notification. And it depends on the Microsoft Push Notification Service which normally sends it first come first serve.
So from the sounds of it, I would look into trying to limit how your application sends the toast notifications. So check if a toast notification has been sent to the phone within a certain amount of time, if so hold of on sending the next one in till that time has past.
Also remember to check if the MPNS actually sent the push notification to the, that will help in determining if the phone might have received the notification
In that link I post it goes into a lot of details about sending and receiving the push notifications.
What I did is this,
public static void ShowToast()
{
try
{
string langKey = CacheManager.getInstance().getDataFromConfigFile(CacheManager.APP_CURRENT_LANGUAGE);
string flag = CacheManager.getInstance().getDataFromConfigFile(CacheManager.APP_UPGRADE_STATUS);
string catalogUpdateFlag = CacheManager.getInstance().getDataFromConfigFile(CacheManager.APP_CATALOG_UPGRADE_STATUS);
CultureInfo ci;
if ((null == langKey) || (langKey.Equals(Utils.LANGUAGE_EN)))
{
ci = new CultureInfo("en-US");
}
else
{
ci = new CultureInfo("fr-FR");
}
AppResources.Culture = ci;
if (!Utils.isNullString(flag))
{
var toast = new ShellToast
{
Title = AppResources.APP_NAME,
Content = getMessageStatus(flag),
NavigationUri = new System.Uri("/MainPage.xaml", System.UriKind.Relative)
};
Logger.log(TAG, ":ShowToast():MessageToUser" + AppResources.APP_NAME + getMessageStatus(flag));
toast.Show();
}
if (!Utils.isNullString(catalogUpdateFlag))
{
var toast = new ShellToast
{
Title = AppResources.APP_NAME,
Content = getMessageStatus(catalogUpdateFlag),
NavigationUri = new System.Uri("/MainPage.xaml", System.UriKind.Relative)
};
Logger.log(TAG, ":ShowToast():MessageToUser" + AppResources.APP_NAME + getMessageStatus(catalogUpdateFlag));
toast.Show();
}
}
catch (Exception ex)
{
Logger.log(TAG, "Exception in ShowToast: " + ex.Message + "\n" + ex.StackTrace);
}
}
private static string getMessageStatus(string flagType)
{
//string flag = CacheManager.getInstance().getApplicationSettings(CacheManager.APP_UPGRADE_STATUS);
string flag = CacheManager.getInstance().getDataFromConfigFile(CacheManager.APP_UPGRADE_STATUS);
string catalogUpdateFlag = CacheManager.getInstance().getDataFromConfigFile(CacheManager.APP_CATALOG_UPGRADE_STATUS);
if (flagType == flag)
{
if (flag.Equals(CacheManager.MAJOR_UPGRADE))
{
return AppResources.APP_UPGRADE_CONFIRM;
}
else if (flag.Equals(CacheManager.MINOR_UPGRADE))
{
return AppResources.APP_UPGRADE_MINOR_CONFIRM;
}
}
else if (flagType == catalogUpdateFlag)
{
return AppResources.APP_CATALOG_CONFIRM;
}
return "";
}
I have taken two different variables to know if its the application upgrade or just the catalogue upgrade(New items will be added to the existing ones). So if there is catalogue upgrade and/or application upgrade user will be notified.

Categories