Push Notifications with PushSharp - the basics - c#

I need to push notifications to tens of thousands of iOS devices that my app installed. I'm trying to do it with PushSharp, but I'm missing some fundamental concepts here. At first I tried to actually run this in a Windows service, but couldn't get it work - getting null reference errors coming from _push.QueueNotification() call. Then I did exactly what the documented sample code did and it worked:
PushService _push = new PushService();
_push.Events.OnNotificationSendFailure += new ChannelEvents.NotificationSendFailureDelegate(Events_OnNotificationSendFailure);
_push.Events.OnNotificationSent += new ChannelEvents.NotificationSentDelegate(Events_OnNotificationSent);
var cert = File.ReadAllBytes(HttpContext.Current.Server.MapPath("..pathtokeyfile.p12"));
_push.StartApplePushService(new ApplePushChannelSettings(false, cert, "certpwd"));
AppleNotification notification = NotificationFactory.Apple()
.ForDeviceToken(deviceToken)
.WithAlert(message)
.WithSound("default")
.WithBadge(badge);
_push.QueueNotification(notification);
_push.StopAllServices(true);
Issue #1:
This works perfectly and I see the notification pop up on the iPhone. However, since it's called a Push Service, I assumed it would behave like a service - meaning, I instantiate it and call _push.StartApplePushService() within a Windows service perhaps. And I thought to actually queue up my notifications, I could do this on the front-end (admin app, let's say):
PushService push = new PushService();
AppleNotification notification = NotificationFactory.Apple()
.ForDeviceToken(deviceToken)
.WithAlert(message)
.WithSound("default")
.WithBadge(badge);
push.QueueNotification(notification);
Obviously (and like I already said), it didn't work - the last line kept throwing a null reference exception.
I'm having trouble finding any other kind of documentation that would show how to set this up in a service/client manner (and not just call everything at once). Is it possible or am I missing the point of how PushSharp should be utilized?
Issue #2:
Also, I can't seem to find a way to target many device tokens at once, without looping through them and queuing up notifications one at a time. Is that the only way or am I missing something here as well?
Thanks in advance.

#baramuse explained it all, if you wish to see a service "processor" you can browse through my solution on https://github.com/vmandic/DevUG-PushSharp where I've implemented the workflow you seek for, i.e. a win service, win processor or even a web api ad hoc processor using the same core processor.

From what I've read and how I'm using it, the 'Service' keyword may have mislead you...
It is a service in a way that you configure it once and start it.
From this point, it will wait for you to push new notifications inside its queue system and it will raise events as soon as something happens (delivery report, delivery error...). It is asynchronous and you can push (=queue) 10000 notifications and wait for the results to come back later using the event handlers.
But still it's a regular object instance you will have to create and access as a regular one. It doesn't expose any "outside listener" (http/tcp/ipc connection for example), you will have to build that.
In my project I created a small selfhosted webservice (relying on ServiceStack) that takes care about the configuration and instance lifetime while only exposing the SendNotification function.
And about the Issue #2, there indeed isn't any "batch queue" but as the queue function returns straight away (enqueue and push later) it's just a matter of a looping into your device tokens list...
public void QueueNotification(Notification notification)
{
if (this.cancelTokenSource.IsCancellationRequested)
{
Events.RaiseChannelException(new ObjectDisposedException("Service", "Service has already been signaled to stop"), this.Platform, notification);
return;
}
notification.EnqueuedTimestamp = DateTime.UtcNow;
queuedNotifications.Enqueue(notification);
}

Related

Azure Service Bus - How to Add Topic Subscriber Programmatically

I'm trying to implement a basic pub/sub system with dynamic subscribers. I need to dynamically register a topic subscriber in my .NET APIs, but it seems like I can only do that manually from the Azure Portal. When my program starts, I want to be able to register a subscriber to a topic in the format of subscribername-{timestamp} because I want to be able to deploy as many staging/dev versions as I want without having to manually create these subscribers each time.
I feel like this is a fundamental feature that I'm just blindly missing. I can do this when working with queues, but if I try to do the same with a topic, I get continuous errors of that subscriber path not found. I have searched the internet to no end and while I have found SOME solutions, they are very old and often not compatible with .NET 5 or the package is deprecated. I'm feeling like I'm going against the grain and missing something with what I'm coming up with, so I'd like to get some input on what the proper practice is for this.
I'm using Azure.Messaging.ServiceBus for publishing and subscribing currently. Below is some code -
var processor = ServiceBusClient.CreateProcessor(TopicName, $"DynamicSubscriber-{DateTime.Now}");
try
{
processor.ProcessErrorAsync += ErrorHandler;
processor.ProcessMessageAsync += MessageHandler;
await processor.StartProcessingAsync();
}
catch (Exception e)
{
await processor.DisposeAsync();
await ServiceBusClient.DisposeAsync();
}
finally
{
Console.WriteLine("Press a key to exit.");
Console.ReadLine();
}
Thank You #PeterBons! Yes, when updating/creating/fetching/deleting the Service Bus entities, ServiceBusAdministrationClient is the client Class to be used.
Also, There are few error details given this article when using the method of Queue with ServiceBusAdministrationClient and this SO Thread.
The ServiceBusTopicSubscription class is used to setup the Azure Service bus subscription. The class uses the ServiceBusClient to set up the message handler, the ServiceBusAdministrationClient is used to implement filters and add or remove these rules. The Azure.Messaging.ServiceBus Nuget package is used to connect to the subscription.

How to force Hangfire to process the queue right now?

I have a queue of fire and forget jobs and my queue is configured to execute every 10 minutes, like this:
var options = new SqlServerStorageOptions
{
QueuePollInterval = TimeSpan.FromMinutes(10)
};
Although the jobs are "fire and forget" i dont want to wait 10 minutes, i want to process the queue right now. How to do this?
I'm assuming you mean that you want to keep your code as is (with the 10 minute PollingInterval) but need a mechanism to force jobs to run immediately when required - in which case I think you should be able to use the Hangfire Dashboard UI, where you can see a detailed breakdown of all jobs, as well as retry/trigger now etc.
To install it, just add the Nuget package: Hangfire.Dashboard.Authorization
and then add the config appropriate to your app type from the following link - it normally just works.
http://docs.hangfire.io/en/latest/configuration/using-dashboard.html
Update - WinForms
For a WinForms project, I think your best option is still the Dashboard (which you can host in an OWIN server hosted on your localhost from within your application - its easier than you might think)
Here are a few references:
https://www.codeproject.com/tips/854141/how-to-self-host-web-api-in-asp-net-web-forms-appl
http://www.c-sharpcorner.com/UploadFile/4b0136/working-with-owin-hosting-and-self-hosting-in-Asp-Net/ (see last section)

Skype API call always cancelled

I have small application which calls phone numbers in Skype and allows to record conversations.
But it doesn't work with Skype versions after 7.5. I tried both Skype4COM and direct API:
For Skype4COM call always gets status clsCancelled, FailureReason is cfrMiscError. Below example code:
Skype skype = new SKYPE4COMLib.Skype();
if (!skype.Client.IsRunning)
{
skype.Client.Start(true, true);
}
skype.Attach(skype.Protocol, true);
Call call = skype.PlaceCall("+17606604690");
For direct API call status is MISSED. I'm using following command to start a call CALL +17606604690. It is possible to start call with somebody from your contact list by starting IM with him and bringing Skype client in focus, but this approach doesn't work for mobile numbers.
I guess Skype API changed after version 7.5, because I see that other applications still able to place calls. I'm also aware about Skype URLs, but they have big delays and won't let you know if call fails.
There is some discussion of this problem here, with a work‐around:
I made a shortcut to only call the skypecall part and surprisingly, if i spam it, it starts in. A triple try-catch cycle does the trick, but to make sure, i just applied force retry until its status becomes "ringing"

How to invoke WCF method programmatically from windows service

I have successfully compiled and run Windows Service with WCF. With installutil, the Windows Service is successfully getting installed and started. I think I am at the end of my development and just need to invoke/call the method DoJobs() inside WCF. I don't need any user interaction and so I don't have any Windows forms or anything. I just want to invoke/call my WCF function programmatically just after serviceHost.Open();
The base address in app.config file is
http://localhost:8733/Design_Time_Addresses/WcfServiceLibrary1/Service1/
I am deploying my WCF from Windows service with the following code.
// Create a ServiceHost for the CalculatorService type and provide the base address.
serviceHost = new ServiceHost(typeof(WcfServiceLibrary1.Service1));
// Open the ServiceHostBase to create listeners and start listening for messages.
serviceHost.Open();
I have also added the service reference and created the below proxy, but not sure of its use.
WcfServiceLibrary1.WCFServiceRef.Service1Client
I have searched tutorials, the examples show how to invoke the WCF function on button_click event of any form after running Windows service. I just want to do that programmatically on start-up of Windows Service.
EDIT: The code inside my DoJobs() fetches the active tab url of firefox with DDE Client, which throws exception when done only in a Windows Service project but runs successfully when done in WCF project. Please see this for reference.
So I made a C#.Net solution with WCF called from a Windows Service and then I called DoJobs() inside Windows Service as shown below.
WcfServiceLibrary1.WCFServiceRef.Service1Client wcfObj = null;
...
protected override void OnStart(string[] args)
{
if (serviceHost != null)
{
serviceHost.Close();
}
serviceHost = new ServiceHost(typeof(WcfServiceLibrary1.Service1));
serviceHost.Open();
if (wcfObj == null)
{
wcfObj = new WcfServiceLibrary1.WCFServiceRef.Service1Client();
wcfObj.DoJobs();
}
}
But, it makes the call happen at the windows service layer, and is throwing the same DdeClient exceptions.
Can the base address url help any way to programmatically invoke DoJobs() in Web-Service? OR there are some other solutions.
Any help is highly appreciated.
Thanks.
This is my aggregated answer from my various comments I made to your post and to Noctis's answer (specifically that we did not know you were using DDE in the OP):
You can't use Dynamic Data Exchange (DDE) in a Windows Service because the latter does not have a message pump. Also DDE requires a Window handle to be passed as a parameter to DDE functions. You can use DDE in programs which do have a message pump does as a WinForms app. See this article for more information
Once your GUI app is running you can either minimize it to a Sys Tray icon or hide the app completely so the user is unaware. Regardless of its visible nature you should have no problem utilising DDE since it will have a message pump.
Now it may be the case you could add a message pump to a Windows Service but I wouldn't recommend it because it falls into the category of because you can do a thing, does not mean you should do a thing. A topic for another time. It's very similar to a recent SO question about how to display a WinForm in a console app - by default you can't and if you managed to you end up with an odd hybrid with much re-inventing of wheels. Not to mention its an ugly hack.
In summary, my best advice is to proceed with a GUI app.
Assuming you have :
// I'm assuming this is your proxy?
var proxy = WcfServiceLibrary1.WCFServiceRef.Service1Client;
// All you need to do is :
proxy.DoJobs() ;
Having seen your update and Micky`s answers, I'm just wondering why you're using DDE. Not sure what your requirements look like, but you can always use your MSMQ to send messages and queue things.

Converting Microsoft EWS StreamingNotification Example to a service

I've been working to try and convert Microsoft's EWS Streaming Notification Example to a service
( MS source http://www.microsoft.com/en-us/download/details.aspx?id=27154).
I tested it as a console app. I then used a generic service template and got it to the point it would compile, install, and start. It stops after about 10 seconds with the ubiquitous "the service on local computer started and then stopped."
So I went back in and upgraded to C# 2013 express and used NLog to put a bunch of log trace commands to so I could see where it was when it exited.
The last place I can find it is in the example code, SynchronizationChanges function,
public static void SynchronizeChanges(FolderId folderId)
{
logger.Trace("Entering SynchronizeChanges");
bool moreChangesAvailable;
do
{
logger.Trace("Synchronizing changes...");
//Console.WriteLine("Synchronizing changes...");
// Get all changes since the last call. The synchronization cookie is stored in the
// _SynchronizationState field.
// Only the the ids are requested. Additional properties should be fetched via GetItem
//calls.
logger.Trace("Getting changes into var changes.");
var changes = _ExchangeService.SyncFolderItems(folderId, PropertySet.IdOnly, null, 512,
SyncFolderItemsScope.NormalItems,
_SynchronizationState);
// Update the synchronization cookie
logger.Trace("Updating _SynchronizationState");
the log file shows the trace message ""Getting changes into var changes." but not the "Updating _SynchronizationState" message.
so it never gets past var changes = _ExchangeService.SyncFolderItems
I cannot for the life figure out why its just exiting. There are many examples of EWS streaming notifications. I have 3 that compile and run just fine but nobody as far as I can tell has posted an example of it done as a service.
If you don't see the "Updating..." message it's likely the sync threw an exception. Wrap it in a try/catch.
OK, so now that I see the error, this looks like your garden-variety permissions problem. When you ran this as a console app, you likely presented the default credentials to Exchange, which were for your login ID. For a Windows service, if you're running the service with one of the built-in accounts (e.g. Local System), your default credentials will not have access to Exchange.
To rectify, either (1) run the service under the account you did the console app with, or (2) add those credentials to the Exchange Service object.

Categories