Connecting BreezeJs to a LightSwitch backend, yeah it works… (part 1/3)

Introduction

I always had a particular interest in “remote procedure calls” or to call it differently in connectivity between disconnected systems. So, when looking back 15 years there were kind of milestones in this field which initially caught my attention but disappointed me after while.

Taking a bath with Soap, Wcf and Odata

The first milestone was XML and soap which promised universal connectivity but it failed. The second one was WCF, a nice  initiative to package soap a bit differently but which lead to drowning by configuration.

Then  OData arrived which excited me a lot. It removed the whole soap packaging overhead and pragmatically aligned the protocol on the application level with the lower level “message” protocol. Or putting it in other words: Getting data is an HttpGet, posting data is an HttpPost. Great, make things as simple as possible but no simpler. No surprise, also LightSwitch uses from version 2 Odata.

I was believing OData was the first real data connectivity holy grail until last year I saw somewhere on a blog that connectivity between BreezeJS and LightSwitch failed. My dream was gone.  The LightSwitch Odata implementation is based on WCF Data Services and is implemented in a decent manner. On the other hand, BreezeJS is the nec plus ultra when it comes to service proxy functionality (with state tracking, caching, Linq-alike querying,…) in a full blow Html5 Single Page Application. Nonetheless, connecting breezeJS to LightSwitch … failed. That’s what we were told. Let’s have closer look and solve the problem.

I’m talking here about a native connection between breezeJS and LightSwitch. BreezeJS can perfectly connect to Odata services based on an EntitySetController. Breeze will connect also perfectly to a LightSwitch app when using a dedicated web api controller which uses internally the LightSwitch Server application context. But that’s too much overhead. I want a direct connection without fuzz., no ServerApplicationContext and no patching server side in the LightSwitch app to get things working.

 

Why BreezeJS?

No BreezeJS course here, Follow the link to learn more, you won’t regret.

Every decent SPA framework needs support for client-side querying, caching and change tracking. LightSwitch has all this on board in both the silverlight and html5 client.

In case you want to interact from  a mainstream SPA framework like Angular or Durandal (or even simply from something custom written entirely in Jquery or javascript) to an existing LightSwitch back-end, you will be very happy with what BreezeJS is offering you.

There are indeed occasions where LightSwitch alone is not enough. Sometimes customers want more pixel precise screen design or want a full blow desktop Single Page app potentially connecting to a legacy lightSwitch app. If breezeJs connectivity is not working, that would be a serious show stopper. With BreezeJS, you can start an application and do the whole prototyping in LightSwitch and later on decide to extend the application with some custom angular pages using BreezeJS for the Odata connectivity.

You get the point?

A smoke test setup between BreezeJS and LightSwitch

Let’s start with creating a dummy LightSwitch app with a Customer data type:

customers

 

Create also a common screen set and eventually add some customers:

browse

 

 

 

Add some scripts in the server project:

Nuget is probably your friend to do this.

So, we’ll need Jquery, Angular, Breeze, Q, Twitter Bootstrap and DataJs

<?xml version="1.0" encoding="utf-8"?>
<packages>
  <package id="AngularJS.Core" version="1.2.24" targetFramework="net45" />
  <package id="bootstrap" version="3.2.0" targetFramework="net45" />
  <package id="Breeze.Angular" version="1.0.1" targetFramework="net45" />
  <package id="Breeze.Angular.Directives" version="1.3.8" targetFramework="net45" />
  <package id="Breeze.Client" version="1.5.0" targetFramework="net45" />
  <package id="datajs" version="1.1.3" targetFramework="net45" />
  <package id="jQuery" version="2.1.1" targetFramework="net45" />
  <package id="Q" version="1.0.1" targetFramework="net45" />
  <package id="System.IdentityModel.Tokens.Jwt" version="1.0.0" targetFramework="net45" />
</packages>

 

Strictly speaking Angular and BootStrap are not really necessary for our smoke test, but they give a cool layout.

This gives for our server project:

solExplorer

 

Create now an html file in the server project. I called it BreezeTrial.html

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <title></title>
    <link href="content/bootstrap.css" rel="stylesheet" />
</head>
<body ng-app="app">

    <div class="container" ng-controller="MainCtr">
        <div class="row">
            <h2>Customers</h2>
        </div>
        <row>
            <table class="table table-hover">
                <thead>
                    <tr>
                        <td>Last Name</td>
                        <td>First Name</td>
                    </tr>
                </thead>
                <tbody>
                    <tr ng-repeat="customer in customers">
                        <td>{{customer.lastName}}</td>
                        <td>{{customer.firstName}}</td>
                    </tr>
                </tbody>
            </table>
        </row>
    </div>

    <script src="Scripts/jquery-2.1.1.js"></script>
    <script src="Scripts/datajs-1.1.3.js"></script>
    <script src="Scripts/angular.js"></script>
    <script src="Scripts/q.js"></script>
    <script src="Scripts/breeze.min.js"></script>
    <script type="text/javascript">
        var app = angular.module("app", []);
        app.value('breeze', breeze);
        breeze.config.initializeAdapterInstance('dataService', 'OData', true);
        breeze.NamingConvention.camelCase.setAsDefault();

        app.controller("MainCtr", function ($scope) {
            $scope.customers = [];
            var em = new breeze.EntityManager("/ApplicationData.svc/");
            var query = breeze.EntityQuery.from("Customers");
            return em.executeQuery(query)
                    .then(querySucceeded)
                    .fail(queryFailed);
            function querySucceeded(data) {
                $scope.customers = data.results;
                $scope.$apply();
            };
            function queryFailed(error) {
                alert("Query failed: " + error.message);
            };
        });
    </script>
</body>
</html>

 

The whole sample is encapsulated in one file. Right a very bad practice but for the purpose of the smoke test it’s just fine.

The html file contains a nice table (with some angular binding and boostrap pepper and salt) and a controller which will retrieve the data from the LightSwitch Odata service.

This is all done as it is described in the BreezeJs documentation.

Unfortunately it doesn’t work:

error

 

what’s happening. BreezeJs is a marvelous library. It uses (similar to lightSwitch) the Odata meta data. So as first step this meta data is retrieved and there it goes wrong already.

But what happens if we request the metadata directly from the browser?

browsermetadata

 

Obviously, that’ working.

So, why is BreezeJS not able to retrieve the metadata correctly from the LightSwitch Odata back-end?

In the next part of this BreezeJS series, we’ll use fiddler to reproduce and solve the problem and than try to find a way how we can do the same in javaScript code.

Stay tuned ….