How to use network triggers to deliver notifications to a lock screen app (XAML)

[This article is for Windows 8.x and Windows Phone 8.x developers writing Windows Runtime apps. If you’re developing for Windows 10, see the latest documentation]

This topic shows how to use a network trigger in a Windows Store app to receive network notifications in the background by a lock screen app. This topic shows you how to register a background task to activate from a network trigger using the ControlChannelTrigger.

What you need to know

Technologies

Prerequisites

  • The following information applies to any connected or network-aware Windows Store app that depends on network connections using TCP to always be connected. This topic applies to apps written in C++/XAML and apps using the .NET Framework 4.5 in C#, VB.NET, or managed C++ on Windows 8 and Windows Server 2012.

    This topic does not apply to apps written in JavaScript or a foreground app in JavaScript with an in-process C# or C++ binary. Background network connectivity using a network trigger with ControlChannelTrigger is not supported by a JavaScript app. For information on background tasks that apply to JavaScript apps, see Supporting your app with background tasks. For information on background network connectivity supported by a JavaScript app, see Staying connected in the background(HTML).

Instructions

Using network triggers in Windows Store apps

There are five steps involved in registering a control channel trigger:

Creating your control channel trigger

1. Create a control channel.

2. Open the transport connection.

3. Associate the transport connection with the control channel.

4. Connect the socket to the endpoint server. For some transports, this may be a connect operation. For some transports, this may be a send operation.

5. Establish a transport connection to your remote endpoint server. After a successful connection to the server, finally synchronize the transport created by your app with lower layers of the operating system by using a specific API as shown in the following code snippet. This API allows the hardware or software slot to be registered with all the underlying layers of the stack that will handle an incoming data packet, including the network device driver.

The following sample registers a control channel trigger to receive notifications of received packets.

private bool RegisterWithRTCBroker(StreamSocket sock) {
       
    ControlChannelTriggerStatus status;
    //
    // Step 1: Create the control channel object.
    //              
    This.channel = new ControlChannelTrigger(
        "channelOne", // Channel ID to identify a control channel. 
        15, // Server-side keep-alive in minutes.
        ControlChannelTriggerResourceType.RequestHardwareSlot);   // Request a hardware slot.
       //
    // Create a control channel trigger.
    //
    BackgroundTaskBuilder controlChannelBuilder = new BackgroundTaskBuilder();
    controlChannelBuilder.Name = “ReceivePacketTaskChannelOne”;
    controlChannelBuilder.TaskEntryPoint = controlChannelBuilderActivationClassName;
    controlChannelBuilder.SetTrigger(channel.PushNotificationTrigger);
    controlChannelBuilder.Register();      
    //
    // Step 2: Open a socket connection (not shown here).
    //
    //
    // Step 3: Tie the transport object to the notification channel object. 
    //
    channel.UsingTransport(sock); 
    // Step 4: Connect the socket (not shown here).
    //
    // Step 5: Synchronize with lower layer to register the transport.
    //
    status = channel.WaitForPushEnabled();        
}

Note  The WaitForPushEnabled method is not related at all to push notifications and WNS.

 

It is important to note that a control channel trigger object will not accept a loopback connection. Hence, the transport connection must be established to another machine.

When a transport connection closes gracefully or due to abortive disconnect, this will result in the cleanup of hardware and software slots. When this happens, there will be one notification related to the disconnect (caused by either remote or the local), but after that there are no further notifications on this channel. The control channel trigger object itself can be reused for a new transport connection.

The second aspect of a network trigger–based lock screen app is to maintain the control channel through transient intermediate network devices and the destination server. This is done by sending periodic keep-alive messages on the persistent transport.

The control channel allows incoming messages to be delivered to apps. In order for this control channel path to be preserved between a client and the remote endpoint server, a keep-alive message may need to be sent at periodic intervals to the remote server. The keep-alive can be initiated from the server or the client.

There are two variables in this path, the network keep-alive interval and the server keep-alive interval. The network keep-alive interval is the time for which intermediate network devices (such as NATs and proxy devices) will preserve the connection state when there is no traffic on the connection. The keep-alive helps ensure that traffic happens to prevent the socket from being closed.

Similarly, the server keep-alive interval is the frequency with which the server endpoint needs to hear from connected clients to consider that the client is still connected.

There are several types of keep-alive intervals that may relate to network apps.

At the lowest level, an app can set a TCP keep-alive option to send TCP keep-alive packets between a client app and a server to maintain an established TCP connection that is not being used. The KeepAlive property on the StreamSocketControl class allows an app to enable or disable this TCP keep-alive option on a StreamSocket. The default behavior for a StreamSocket is that TCP keep-alive is disabled. The MessageWebSocket , StreamSocketListener, and StreamWebSocket classes do not have an option to enable TCP keep-alive and TCP-Keep alive is disabled by default. Similarly, the HttpClient class and the IXMLHTTPRequest2 object do not have an option to enable TCP keep-alive and TCP keep-alive is disabled by default.

In the context of the ControlChannelTrigger class, there are two other keep-alive intervals that have an impact.

  • Server keep-alive interval - This refers to a keep-alive interval in minutes that the network app registers with the system on how often to be woken up when the app has been suspended. The system will wake up the app based on the value set for this keep-alive interval. This value is represented by the ServerKeepAliveIntervalInMinutes property on a ControlChannelTrigger class and is set by the constructors to initialize a new ControlChannelTrigger instance. This value is considered a server keep-alive interval since a network app might normally set this based on known behavior of the server to which the app has established a TCP connection. For example, if it is known that a Web server will disconnect and drop TCP connections if there is no data sent by the app for 30 minutes, the network app could set this server keep-alive interval to say 25 minutes.
  • Network keep-alive interval - This refers to an internal keep-alive timer maintained by low-level network components in the TCP stack based on current network conditions. This value represents the value needed by network intermediaries to keep the TCP connection intact (or HTTP connection in the case of a proxy server). These network intermediaries represent hardware and devices such as network proxies and network address translators. A network app cannot set this value, since this value is determined dynamically by low-level system components in the TCP stack. However, a network app can indicate to the system that the network keep-alive timer should be decreased if established TCP connections are regularly dropped by calling the DecreaseNetworkKeepAliveInterval method on a ControlChannelTrigger class.

The registration for the keep-alive trigger can be done as part of the control channel registration. You can extend the code snippet above to add support for keep-alives.

Maintaining your control channel

The following sample registers a control channel trigger for keep-alives.

private bool RegisterWithRTCBroker(StreamSocket sock) {
       
    ControlChannelTriggerStatus status;
    //
    // Step 1: Create the control channel object.
    this.channel = new ControlChannelTrigger(
        "channelOne", // Channel ID to identify a control channel. 
        15, // Server side keep-alive in minutes.
        ControlChannelTriggerResourceType.RequestHardwareSlot);   // Request a hardware slot.
    //
    // Create control channel task (shown in previous snippet).
    //

    // Create keep-alive task.
    BackgroundTaskBuilder keepAliveBuilder = new BackgroundTaskBuilder();
    keepAliveBuilder.Name = “KeepAliveTaskChannelOne”;
    keepAliveBuilder.TaskEntryPoint = KeepAliveTaskActivationClassName;
    keepAliveBuilder.SetTrigger(channel.KeepAliveTrigger);
    keepAliveBuilder.Register();
       
    //
    // Step 2: Open a socket connection (not shown here).
    //

    //
    // Step 3: Tie the transport object to the notification channel     //      object. 
    channel.UsingTransport(sock);
    // Step 4: Connect the socket (not shown here).

    //
    // Step 5: Synchronize with lower layer to register the transport.
    status = channel.WaitForPushEnabled();        
}

Note  The WaitForPushEnabled method is not related at all to push notifications and WNS.

 

Windows will determine the optimal network keep-alive interval based on heuristic measurements for a given network. However, the server keep-alive interval must be provided by the app while registering the control channel trigger. The minimum server keep-alive time that can be provided by an app is 15 minutes. If an app tries to set a value lower than 15 minutes, an exception will be thrown.

The operating system accounts for both these values and chooses an optimum rate at which to send keep-alives for a given app on a given network that will preserve the control channel connection between client and the remote endpoint.

Note that the network keep-alive interval may be much lower than the server keep-alive provided by the app. The operating system determines the optimal network keep-alive interval and chooses the lower of the two values. This optimal value is used for the keep-alive interval by the operating system to coalesce app use of CPU and network in order to improve battery life.

The keep-alive can be initiated by the client or the server. If the keep-alive is initiated by the server, the incoming notification message on the control channel will trigger a control channel trigger background task. This works well as long as the control channel is open; if the network connection is lost the app would not be aware of this loss, because it will be waiting for the incoming packet. To avoid this, an app can use the keep-alive trigger as a fallback to check for connectivity and re-establish the control channel if necessary. Note that the app has to be either running or suspended and the control channel must be present in order for any incoming message to trigger the background task.

Note that the keep-alive specified here is the app-level keep-alive, and is different from the TCP keep-alive, which is not used in this keep-alive trigger.

What if the keep-alive is too long for your app?

If your app has too many network connection losses, it is possible that the keep-alive interval chosen for the app is too long. In order to enable an app to provide this feedback, the DecreaseNetworkKeepAliveInterval method is provided as part of the ControlChannelTrigger object.

When an app calls DecreaseNetworkKeepAliveInterval, the operating system will reduce the keep-alive interval for the network triggers created for the corresponding channel ID. It will cache this value in a per-network location for a month. The app should call DecreaseNetworkKeepAliveInterval only if it determines that there is frequent connection loss. If necessary, the app may invoke the DecreaseNetworkKeepAliveInterval method more than once to request that Windows further lowers the keep-alive interval. However, Windows enforces a minimal value for the interval. If even after invoking DecreaseNetworkKeepAliveInterval the app continues to see connection losses on a given network, it may choose to not provide real-time connectivity options to its user. Since apps are sandboxed in terms of CPU and network I/O, frequently invoking this function will affect app performance.

There may be cases where Windows is still in process of measuring the network keep-alive interval for the current network, and it would best for the app to avoid calling the DecreaseNetworkKeepAliveInterval method. The app can detect if the measurement of the network keep-alive has converged by retrieving the CurrentKeepAliveIntervalInMinutes property to determine the current Windows estimate and see if it has changed compared to the previous value.

Some apps may prefer to know the current network keep-alive interval that is used by Windows. For such apps, the CurrentKeepAliveIntervalInMinutes property can be used to retrieve this information.

The following sample queries the current keep-alive interval.


UInt32 KAInt = CurrentKeepAliveIntervalInMinutes();

The CurrentKeepAliveIntervalInMinutes property returns the keep-alive interval in minutes. One example of an app using this value is for server-side keep-alive. The client app can use a value lower than the current keep-alive interval to set its server-side keep-alive interval. This way if the server does not respond within this interval, the client keep-alive timer will fire and the app can re-establish its control channel.

Note  The network keep-alive interval can have a minimum value of 4 minutes and a maximum value of 24 hours. If a timeout occurs on a connection at a value lower than 4 minutes, the connection cannot be maintained using a ControlChannelTrigger and the app will fail to maintain the connection when in the background.

 

Note  Keep-alive intervals are coalesced across Windows for all apps using network triggers. If an app is currently scheduled for a background task to run in response to a server keep-alive timer and another app with a similar server keep-alive timer triggers within a tolerance period, then the background tasks are run for both apps. The tolerance is never pushed past the original expiration of the server keep-alive timer of any app, so the background task is guaranteed to run within the set server keep-alive interval even with coalescing.

 

Previous steps

For more information on how to create a lock screen app to receive background network notifications that use network triggers, see Quickstart: Create a lock screen app that uses background network triggers.

Further steps

For more information on how to write a background task to receive background network notifications that use network triggers, see How to write a background task for a network trigger.

For more information on how to re-establish a network trigger and a transport connection, see How to re-establish a network trigger and transport connection.

For more information on using a StreamSocket with a network trigger, see How to use a stream socket with a network trigger.

For more information on using a MessageWebSocket or StreamWebSocket with a network trigger, see How to use a WebSocket with a network trigger

For more information on how to use HttpClient with a network trigger, see How to use HttpClient with a network trigger.

For more information on how to use with a network trigger, see How to use IXMLHttpRequest2 with a network trigger

For more information on guidelines and checklists for using network triggers, see Guidelines and checklist for using network triggers.

Other resources

Adding support for networking

Background Networking

Lock screen overview

Staying connected in the background

Supporting your app with background tasks

Troubleshooting and debugging network connections

Reference

ControlChannelTrigger

HttpClient

HttpClientHandler

IXMLHTTPRequest2

MessageWebSocket

StreamSocket

StreamWebSocket

System.Net.Http

Windows.ApplicationModel.Background

Windows.Networking.Sockets

Samples

Background task sample

ControlChannelTrigger HttpClient sample

ControlChannelTrigger with IXMLHTTPRequest2 sample

ControlChannelTrigger TCP socket sample

ControlChannelTrigger StreamWebSocket sample

Lock screen apps sample