Push notification is the DevForce implementation of a publish-subscribe service. It allows client applications to subscribe to user-defined services on the EntityServer and to receive notifications from the server when an event of interest occurs.
The push service is similar to the remote server method call feature, with the difference that the remote server method call is a request-response call, meaning that an individual client makes a request and then awaits (either synchronously or asynchronously) the response from the server.
With the push service, the client application subscribes to a user-defined service, which will then send event notifications to subscribers on a periodic basis of its choosing. For example, a push service can send out "broadcast" messages to all its subscribers, or to only subscribers meeting the criteria for the specific event. The "event" is application-defined, it could be the receipt of a file, an update to a database table, a timer elapsed - any occurrence for which it needs to notify subscribers.
A push service is started upon the first client subscription. Once started, the service can run indefinitely and support any number of subscribing clients. The service runs on its own thread and can perform any processing desired, including starting additional threads or processes. The service will be stopped automatically after the last client unsubscribes.
The class holding your service's entry method should be in an assembly deployed to the EntityServer. In addition, the method must meet the following criteria:
1) The method signature must conform to the ServerNotifyDelegate;
C# | public delegate void ServerNotifyDelegate(Guid serviceKey, INotificationManager notificationManager, EntityManager serverEntityManager); |
VB | Public Delegate Sub ServerNotifyDelegate(ByVal serviceKey As Guid, _ ByVal notificationManager As INotificationManager, _ ByVal serverEntityManager As EntityManager) |
2) The method must be decorated with the [AllowRpc] attribute and must be static;
Here's an example:
C# | [AllowRpc] public static void MultiStepService(Guid serviceKey, INotificationManager notificationManager, EntityManager entityManager) { // ... } |
VB | <AllowRpc> Public Shared Sub MultiStepService(ByVal serviceKey As Guid, _ ByVal notificationManager As INotificationManager, _ ByVal entityManager As EntityManager) ' ... End Sub |
All three parameters are provided to the method by DevForce:
serviceKey - Server-assigned key which uniquely identifies this service.
notificationManager - The INotificationManager used to obtain subscriber information and send notifications to client subscribers.
serverEntityManager - A server-side EntityManager.
To subscribe to a push service, the client must call the EntityManager’s RegisterCallback method:
C# | _entityManager.RegisterCallback( "DomainModel.LongRunningProcedure, DomainModel", /* Type name */ "MultiStepService", /* Method name */ LongRunningProcedureNotification, /* the callback */ "lrp"); /* user token */ |
VB | _entityManager.RegisterCallback( _ "DomainModel.LongRunningProcedure, DomainModel", _ "MultiStepService", _ LongRunningProcedureNotification, _ "lrp") ' user token - the callback - Method name - Type name |
Once registered, the client remains subscribed to the service until either closing or calling CancelCallback.
You can also pass user-defined arguments to the push service when registering. Here's a sample passing a single parameter:
C# | _entityManager.RegisterCallback( "DomainModel.OrderWatcher, DomainModel", /* Type name */ "NewOrderService", /* Method name */ OrderPushCallback, /* the callback */ _owToken, /* user token */ employeeId); /* client argument(s) */ |
VB | _entityManager.RegisterCallback( _ "DomainModel.OrderWatcher, DomainModel", _ "NewOrderService", _ OrderPushCallback, _ _owToken, _ employeeId) ' client argument(s) - user token - the callback - Method name - Type name |
You can pass any number of arguments, but all types must be serializable, defined on both the client and server, and known types.
These arguments are available in the push service on the NotificationSubscriber. The service can retrieve all subscribers by calling the GetSubscribers method on the NotificationManager, passing the assigned service key:
C# | foreach (var subscriber in __notificationManager.GetSubscribers(__serviceKey)) { // Obtain arguments passed from client when registering. var args = subscriber.ClientArguments; // ... } |
VB | For Each subscriber In __notificationManager.GetSubscribers(__serviceKey) ' Obtain arguments passed from client when registering. Dim args = subscriber.ClientArguments ' ... Next subscriber |
When the service has a notification to send to one or more subscribers, it does so with the Send method on the NotificationManager.
To broadcast to all subscribers:
C# | __notificationManager.Send(__serviceKey, "Some message here", "And another")); |
VB | __notificationManager.Send(__serviceKey, "Some message here", "And another")) |
To send a notification to a specific subscriber, pass the NotificationSubscriber with the Send call:
C# | __notificationManager.Send(__serviceKey, subscriber, "One message", "And a second"); |
VB | __notificationManager.Send(__serviceKey, subscriber, "One message", "And a second") |
You can pass any number of notification arguments to clients, and they can be of any type. As with the client arguments on the subscription, these types must be defined on both client and server, serializable, and identified as known types.
On the client, the notifications will be received by the callback method which was specified when registering for the service. The callback method takes a SubscriptionOperation which will indicate if an error occurred or contain a NotificationData array containing the data sent from the server.
C# | private void OrderPushCallback(SubscriptionOperation op) { // Get the first argument and display. string msg = op.NotificationData[0].ToString(); MessageBox.Show(msg, "Received from OrderWatcher", MessageBoxButton.OK); |
VB | Private Sub OrderPushCallback(ByVal op As SubscriptionOperation) ' Get the first argument and display. Dim msg As String = op.NotificationData(0).ToString() MessageBox.Show(msg, "Received from OrderWatcher", MessageBoxButton.OK) End Sub } |
To be able to use the push feature, you must first enable it on the server. You can use DevForce default settings by simply setting the following flag in the ideablade.configuration section of the server’s config file:
C# | <notificationService enabled="true" /> |
You can also customize this configuration by defining the service endpoints in the system.serviceModel section of the config file, or implementing a custom ServiceHostEvents class.
As of version 6.1.15, you can also configure the default "cleanup" interval and throttle this behavior. By default, a cleanup is performed every 10 minutes to look for disconnected client applications which should be removed from the server's subscription list. Also by default, all subscribed clients are "pinged" during this cleanup. To override these defaults you can modify the notificationService settings. For example, this sets the interval to 3 minutes and the throttle to 25:
C# | <notificationService enabled="true" cleanupInterval="3" cleanupThrottle="25" /> |
See the topic app.config in detail for additional information.
You must specify the client port number in the ideablade.configuration section of the app.config file:
C# | <notificationService clientPort="9012"/> |
Choose any port number not already in use, and be sure to open the port in your firewall.
If you need to customize the default configuration you can fully define the push endpoint in the serviceModel section of the configuration file, or implement a custom ServiceProxyEvents class.
When using push in a WinClient application a duplex WCF channel is used and the callback address must be registered. Because HTTP addresses are secured resources you will need to enable access for non-administrative users. You can use the Netsh command line tool to register the callback address for a user:
1) Open a command prompt using “Run as administrator” and enter:
2) netsh http add urlacl url=http://+:9012/ user=DOMAIN\USERNAME
...where 9012 is the port and DOMAIN\USERNAME is the user account to be granted access.
In Silverlight applications, no configuration information in the app.config is provided. If you need to customize the default configuration you can fully define the push endpoint in the ServiceReferences.ClientConfig file, or implement a custom ServiceProxyEvents class.