Background
Often times, our sales team will approach a client and talk up our integration with blue-tooth peripherals, on device bar-code scanners, network printers, etc., usually displaying the capabilities of the latest brand-name mobile device. I have been in rooms when these sales discussions are taking place, and it is really a joy to see the excitement our potential customers have as the wheels start turning; each person thinking of how our integration with X will solve some Y set of problems their company is facing.
The product my company develops is designed to be cross-platform. Built on web technologies, we are able to support Android, iOS, PC, Mac, or nearly any other system that runs a proper web browser.
Although HTML and JavaScript get us pretty far, there is always going to be some area where it’s necessary to have a deeper interaction with the application’s host system. For iOS and Android we have been using Cordova (although having to jump through hoops with each release). For Windows hardware integrations, our options have been pretty poor.
A couple weeks go by, the sale is finalized, the contract ink is dry, and the project kicks off. Now our integration and development teams start to encounter hurdles.
“We don’t support Android”
“Our entire enterprise is required to use Internet Explorer”
“We already have a support contract with Dell”
“We plan to use Windows Mobile handhelds we purchased 5 years ago”
“Our users are allowed and encouraged to use their own mobile devices”
Luckily, these types of problems are where web technologies really shine. “OK, no problem. We ensure you that our application with all desired integrations work well on whatever platform you choose.” Making that promise a reality is where I find a lot of enjoyment in my job.
Why .NET
Out of all of our active projects, Windows is probably the least requested platform. However, we still do our best to make sure all of the features our sales team advertised on Android and iOS devices are available on Windows.
To make it happen, it’s really hard to avoid .NET
- It’s much easier to develop with than C++; and, for the same reason, many hardware manufacturers offer .NET SDKs to integrate with their products.
- Microsoft always includes a .NET runtime on default installations of Windows.
- Getting help is easy.
Offline GPS (Hurdle #1)
The hurdle that spawned the creation of this article is related to GPS and location services on Windows. Modern browsers already include a location service, and they work pretty well. But, the location API built into desktop browsers turned out to be very poor for a few of our customers.
Most location services work by looking up the registered location of your IP address or by calculating your location based off of nearby wireless access points (yes, the location of your home wifi is part of a giant database). To do these lookups, your pc is required to have an active internet connection.
Our product is designed to work just as well with and without an internet connection, so for these customers we had to find a way to make device location available to browsers without requiring an internet connection. To the surprise of no-one, browsers do not readily fetch information from hardware GPS chips/dongles. We had to create our own solution to bridge the gap between GPS hardware and the browser.
Our solution
Luckily for us, Microsoft had already done a lot of the work. Windows includes an OS level location API that many GPS devices happily register themselves with. All we had to was access it and make it available to the browser.
We decided early that creating browser plug-ins and extensions was an unacceptable solution. None of us felt like, or have the time, to maintain extensions for each of the major browsers. Nor was there any common API to directly access arbitrary system information from Windows (any technology like that would pose a huge security risk).
The solution we created out of necessity ended up being a solution we could repeat across many use cases.
We use .NET to fetch any information from Windows that we desire (Device Location in this case). We then use use .NET to create a Windows Web Service to expose that information over HTTP. Browsers can make xhr requests to this web service on localhost and receive the location data as a JSON string.
Pretty clever. We had now made nearly any Windows information available to the browser and we gladly offered the software we created to the public. https://github.com/DataSplice/locatinator
The “locatinator” worked for us for a number of years until recently Google Chrome threw us a curve-ball.
HTTPS (Hurdle #2)
Google Chrome is really doing the world a favor by enforcing security, but this particular security feature caused us some temporary headache.
First, Chrome started enforcing HTTPS security if your website/app wanted access to the device camera/fileupload api. Then they added the same enforcement for access to device location. In response, we started encouraging our customers to switch to HTTPS, either in the form of self-signed certificates within our server software, or by using secure reverse-proxies with SSL certificates provided by trusted Certificate Authorities.
Secondly, Chrome started enforcing that any site served with HTTPS can only access other sites served by HTTPS. This became a problem for our locatinator.
Our web service had always been hosted without HTTPS and we didn’t have a mechanism for securing it. From then on, HTTPS secured customer sites could no longer make requests to our GPS web service.
I took it upon myself to re-vamp our Locatinator.
EdgeJS
On Windows, we also maintain a client built with NW.JS (NW.JS is, essentially, an embedded Chrome browser with a super-powered JavaScript inferface provided by Node.JS). We have dreams about making this NW.JS client our go-to platform on Windows, but we really didn’t have any compelling features to make it attractive. Until now.
Our lead developer recommended that I look into a technology called EdgeJS. http://tjanczuk.github.io/edge/
Every person in our development team loves to stay up-to-date with the latest technology and programming concepts. EdgeJS was something our lead developer had read about but didn’t have the time to research. Having set aside the time to do so, I was able to read up on it and run through a couple of example programs. Turns out that it’s pretty slick.
EdgeJS is a set of JavaScript libraries and cross-platform binaries that allow the transfer of data between Node.JS and .NET (as well as various other languages). You can script .NET inside of Node.JS and you can script Node.JS inside of .NET. In our case, we already had the .NET capabilities, we just needed to make it available to JS so our application could consume the .NET GPS data.
To work with .NET, you can choose to write your C# code directly within your JavaScript as a function.
Or, you can integrate with existing .NET dll libraries by calling their methods directly.
As the example above states, the .NET method must be a Function that takes any object as input and outputs a Task that provides a resulting object. This lets Node.JS execute .NET methods asynchronously.
I quickly realized that using EdgeJS is going to take care of two of our problems. EdgeJS will allow us to integrate our .NET with NW.JS without a web service, which makes our NW.JS client an attractive option for customers. To support browsers, EdgeJS will also allow us to implement our web service with Node.JS instead of C# (Setting up HTTPS on Node.JS web servers is incredibly easy).
Locatinator 2.0
Before starting to integrate with NW.JS, I wanted to focus on the locatinator web service first.
All of the code for this project is temporarily located at https://github.com/WebeWizard/ds-webservice
.NET
In the lib
folder you will find the .NET code that compiles to a dll.
Most of the .NET class is just standard code, but for convenience I created a wrapper to make the class EdgeJS friendly.
|
|
EdgeGeoProvider
takes the normal locatinator class and creates a new instance of it. Without this “provider”, we wouldn’t be able to maintain state within an instance of the locatinator object.
EdgeWrapper
takes the provider and wraps it in an EdgeJS friendly function. Now I only have to make one call from JavaScript to expose all of the functionality of the provider.
Node.JS
The code for Node.JS is written in CoffeeScript and then compiled to JavaScript for distribution.
I won’t post the coffeescript code here, but if you look at the Github project, you can find the code primarily in server.coffee
, providers.coffee
, and locatinator.coffee
.
locatinator.coffee
contains the integration with EdgeJS that gets ahold of the .NET provider and allows us to make calls to the provider’s methods.
providers.coffee
is responsible for initializing providers and adding their sub-routes to the server route map.
server.coffee
provides the Node.JS web server and serves data requested by routes.
Routes like ‘\gps\location’ are added to a route map by providers.coffee
. In this case, ‘gps’ refers to the locatinator provider, and ‘location’ refers to a sub-route within that provider that serves location data.
Distribution
I decided not to use Gulp to manage builds on this project. It’s all for Windows, so there is no need to support cross-platform building and distribution. Instead I am using windows .bat files to compile the C# code, CoffeeScript code, and make a release folder.
No real hurdles here except file size. I can’t expect our customers to have a Node.JS runtime installed on their devices so I have to include one. The executable for Node.JS is about 13MB. The dependency on EdgeJS was massive, around 40MB. Digging in the EdgeJS folders I saw that a lot of the size due to edgejs including all of the different cross-platform binaries by default. Since I am only targeting Win32 and a specific version of Node, I was able to remove most of the cross-platform files from my release folder. All together the release is about 26MB and zips down to 19MB. That still seems large for just the locatinator, but as we add more types of providers to the web service, it won’t seem so bad.
I also distribute a self-signed certificate so Node.JS can provide an HTTPS secured server, which solves our Chrome problems.
Conclusion
I’m pretty proud of myself for this one. The EdgeJS friendly .NET dlls that provide Windows data to the web service are now also available to our NW.JS client, where integration should be easy.
There is still a bit of work to be done, but mostly it’s on the node.js server side. EdgeJS took all of the hard work out of integrating with Windows.
Thanks for reading!