Writing Windows 10 App Services in JavaScript

Editor’s note: The following post was written by Windows Platform Development MVP Guillaume Leborgne

What is an App Service ?
Windows 10 introduced a bunch of new ways for applications to communicate with each other. One way is to implement "App Services." App Services is a request/response model where one app can call a service located within another app. App Services enables communication between apps, but also with the system. If you want to implement interactive scenarios with Cortana, you will have to implement an App Service to provide data to Cortana.

If you're the kind of person who prefer code rather than blah blah, you may head directly to the github repository with sample applications.

App Services use the same infrastructure as BackgroundTasks, and most of the logic and implementation details still apply. It means that when your service is called, you don't have the whole application running, but only your service. It also means that your application doesn’t communicate directly with your App Service. For example, your application does not get notified when your service is called or terminated.

In all resources I can find (Build session, Channel 9 videos, samples, etc.), App Services are implemented in C#. Those resources are really helpful (especially this one on Channel 9), but if (like me) you are writing apps in HTML and JavaScript, it is likely that you prefer writing those services in JavaScript and share business code with the rest of your application. Porting C# resources to JavaScript is actually very easy. In this post, we will dive into implementing an App Service in Javascript, based on a C# sample from Microsoft Virtual Academy.

Show me some code!
In a Windows Web Application (Windows application written in HTML and JavaScript), a background task, therefore an App Service, should be thought of as a special Web Worker (no postMessage with it unfortunately). It's a standalone JavaScript file that will get caught independently by the system.

The first step to implement your App Service is to create this file. As with web workers, you could use "importScripts" to reference any code you want to share between your app and the service. Be aware that, like with Web Workers, there is no "window" or "window.document" objects inside your background task or app service. The global context points to a completely different beast, and there is no DOM.

Inside your task or service, you will access the current instance of the BackgroundTask object using WinRT APIs, and get a deferral on it to control the lifecycle of your service. As with background task, your service can also be canceled by the system if it needs to recover memory, or if battery is running low on the device. Your task instance provides a "cancel" event that will get caught in such cases.

A minimalistic background task/app service would look like this
var backgroundTaskInstance = Windows.UI.WebUI.WebUIBackgroundTaskInstance.current;
var triggerDetails = backgroundTaskInstance.triggerDetails;
var bgtaskDeferral = backgroundTaskInstance.getDeferral();

function endBgTask() {
    backgroundTaskInstance.succeeded = true;
    bgtaskDeferral.complete();
    bgtask.close();
}

backgroundTaskInstance.addEventListener("canceled", function onCanceled(cancelEventArg) {
    return endBgTask();
});

Now we must declare this file as an App Service. For that, we must add an extension to our application in its manifest, pointing to our JavaScript.

<Applications>
    <Application Id="App" StartPage="default.html">
        ...
        <Extensions>
            <uap:Extension Category="windows.appService" StartPage="js/appservice.js">
                <uap:AppService Name="MyJavascriptAppService"/>
            </uap:Extension>
        </Extensions>
    </Application>
</Applications>

As you can see, we provide the path to our JavaScript file, and we are giving a name (MyJavascriptAppService) to the App Service.

Now we must implement the service logic. To do that, we will check the trigger details on our background task, and register for a request event. When the event gets activated, we receive an App Service request. This request will contain a message (with request arguments), and a sendResponseAsync method to reply to the caller. On both sides, the values in the request and in the response are provided with a ValueSet object.

//check that the app service called is the one defined in the manifest. You can host
//multiple AppServices with the same JavaScript files by adding multiple entries in the application manifest
if (triggerDetails && triggerDetails.name == 'MyJavascriptAppService') {
    triggerDetails.appServiceConnection.onrequestreceived = function (args) {
        if (args.detail && args.detail.length) {
            var appservicecall = args.detail[0];
            //request arguments are available in appservicecall.request.message
            var returnMessage = new Windows.Foundation.Collections.ValueSet();
            returnMessage.insert("Result", 42);
            appservicecall.request.sendResponseAsync(returnMessage)
        }
    }       
}

Calling your App Service
The app calling your service can be any app. If you want to restrict access, you will have to implement your own security mechanism. As you may have understood, the caller and the callee don't have to be written in the same language. You can call a service written in C++ from a JavaScript app. All data is passing through Windows APIs.

Calling the app service require some arguments: the caller should provide the package family name (PFN) of the target application, and the name of the App Service (as declared in the target's app manifest). If you don't know your PFN, you can get it through WinRT APIs by calling "Windows.ApplicationModel.Package.current.id.familyName" in your service application.

Using the PFN and service name, you will first get a connection to your App Service, and register to the "serviceclosed" event to be notified if your service terminate.

function getServiceConnection(){
    var connection = new Windows.ApplicationModel.AppService.AppServiceConnection();
    connection.appServiceName = "MyJavascriptAppService";
    connection.packageFamilyName = "...your PFN here...";

    return connection.openAsync().then(function(connectionStatus){
        if (connectionStatus == Windows.ApplicationModel.AppService.AppServiceConnectionStatus.success) {
            connection.onserviceclosed = serviceClosed;
            return connection;
        }
        else {
            return WinJS.Promise.wrapError({ message: 'service not available' });
        }
    });
}

Once you get a valid connection, you will be able to send requests to the service
function callService(){
    return getServiceConnection().then(function (connection) {
        var message = new Windows.Foundation.Collections.ValueSet();
        message.insert("Command", "CalcSum");
        message.insert("Value1", 8);
        message.insert("Value2", 42);

        return connection.sendMessageAsync(message).then(function (response) {
            var e = response;
            if (response.status === Windows.ApplicationModel.AppService.AppServiceResponseStatus.success) {
                document.getElementById('result').innerHTML = 'calculated ' + response.message.Result;
                
                return response.message;
            }
        });
    });
}

And voilà! You're ready to go. A picture is worth a thousand words, so I put a sample with service and caller apps on github for you.

Debugging your service
If you grab the sample, you can see how easy it is to debug your service. If you configure the solution to run both caller and callee on debug, you can set breakpoints in your app service. If you don't want to run the full service app, you could also edit the properties of the project hosting the service. In the debugging section, you could set "Launch Application" to false. In that case, when you run debug for both apps, you will only see the caller application starting, but your breakpoints in the app service will get called appropriately.

 

About the author

Guillaume Leborgne focuses on Windows client development, HTML5 and ASP.Net, and is an active speaker, webcaster, blogger and mentor.