Supporting OData $inlinecount & json verbose with Web API OData

OData, the open data protocol is an awesome protocol for exposing data from your server tier, because it allows the caller to use special query arguments to filter, sort, select only particular columns, request related entities in a single call, and do paging.

Basically, this means you end up with an “open” data service API, where you literally just expose data and leave it up to the client to dictate the specific use case. Whether you want to do that is kinda negotiable for your own client, but when you’re building an application where you want to really want to support and nurture users building 3rd party integration tools, OData is the perfect candidate to build an “I don’t know beforehand what scenarios you want to accomplish” API.

Furthermore, creating an OData read service is really simple, you take the Microsoft.AspNet.WebApi.OData nuget package, you expose an IQueryable in your Controller, and you slap on the [EnableQueryAttribute]:

    public class QueryController : ApiController

        public IQueryable People()
            return this.dbContext.People;

So here’s the problem: suppose there’s 100 people in the database, with ages evenly divided from 1 – 100. The caller requests all people with age > 50 ($filter=age gt 50). We also applied a page-size (which you should really always do to avoid self-inflicted DDOS attacks) of 25 maximum records in a single response. At this point, we do not want to just send back 25 records, but we also want to inform the caller that we have a applied a page-size and there are really 50 people that match his search criteria, and wouldn’t it be nice if we can also inform the caller how to get the next page?

The good news is: according to the OData spec, you can! By returning an “OData verbose” response (“verbose” being the opposite of “light”, which is the new OData default response), you can send back a result not only containing the actual results but additional metadata like the number of people that matched your search criteria, and how to get the next page of results.

The really bad news is: the Web API OData implementation does not support the $inlinecount query parameter (which instructs the server to send back the count after filtering but before paging). OUCH!

Weirdly, after following a dozen blog posts (like this really good one ) I stumbled upon the fact that this is only partly true… The Web API Odata implementation does in fact support the $inlinecount query parameter, however it does not in any way support actually sending back the JSON verbose format where the caller actually gets to see the query parameter…
Wait, whot?
A caller can send the $inlinecount, the EnableQueryAtrribute (which really does all the heavy work) will correctly handle it, but instead of properly sending the count to the client it will simply keep it in memory and send only the results back. Same story with the link to the next page of records, when you implement a PageSize.
So the good news is: to re-enable the $inlinecount, or in other words: send back a more verbose response to the user, you can make your own EnableQueryAttribute:

using Newtonsoft.Json;
using System;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Web.Http;
using System.Web.Http.Filters;
using System.Web.Http.OData;
using System.Web.Http.OData.Extensions;
using System.Web.Http.OData.Query;

namespace Lobsta.webapi
    internal class ODataVerbose
        public IQueryable Results { get; set; }

        [JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
        public long? __count { get; set; }

        [JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
        public string __next { get; set; }
    public class QueryableAttribute : EnableQueryAttribute
        public bool ForceInlineCount { get; private set; } 
        public QueryableAttribute(bool forceInlineCount = true, int PageSize = 25)
            this.ForceInlineCount = forceInlineCount;
            //Enables server paging by default
            if (this.PageSize == 0)
                this.PageSize = PageSize;
        public override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext)
            //Enables inlinecount by default if forced to do so by adding to query string
            if (this.ForceInlineCount && !actionExecutedContext.Request.GetQueryNameValuePairs().Any(c => c.Key == "inlinecount"))
                var requestUri = actionExecutedContext.Request.RequestUri.ToString();
                if (string.IsNullOrEmpty(actionExecutedContext.Request.RequestUri.Query))
                    requestUri += "?$inlinecount=allpages";
                    requestUri += "&$inlinecount=allpages";
                actionExecutedContext.Request.RequestUri = new Uri(requestUri); 

            //Let OData implementation handle everything

            //Examine if we want to return fat result instead of default
            var odataOptions = actionExecutedContext.Request.ODataProperties();  //This is the secret sauce, really.
            object responseObject;
            if (
                && actionExecutedContext.Response.TryGetContentValue(out responseObject)
                && responseObject is IQueryable)
                actionExecutedContext.Response =
                        new ODataVerbose
                            Results = (IQueryable)responseObject,
                            __count = odataOptions.TotalCount,
                            __next = (odataOptions.NextLink == null) ? null : odataOptions.NextLink.PathAndQuery

        private bool ResponseIsValid(HttpResponseMessage response)
            return (response != null && response.StatusCode == HttpStatusCode.OK && (response.Content is ObjectContent));

Note: this is highly opinionated sample code, it always uses a page size of 25, and always returns the inlinecount… Change to your liking, by example checking if the requested format is jsonverbose, to be OData spec compliant
Finally, replace the ‘EnableQuery’ attribute with our custom one:

    public class QueryController : ApiController

        public IQueryable People()
            return this.dbContext.People;

Putting it to the test, I called: /api/query/people?$orderby=name&$filter=age gt 50&$inlinecount=allpages again and now correctly receive my requested metadata:

   {"age":51,"name":"Anna"} /* More results were included of course */

Coding tip #2: fail fast, don’t fail, don’t worry

Facebook recently pulled the plug on one of their data centers…
On purpose.

The idea was to investigate how well they could recover from live failures.

We developers, and beginning developers especially, sometimes have this weird notion that code should be perfect and withstand any storm. Truth is, something can and will always go wrong at some point in time, and we should stop fearing it.

The first, most noticeable form of something going wrong, is an exception that’s being thrown. Beginning developers will often shy exceptions. They’re cryptic and are more likely to happen in the middle of a demo than while developing…

Fail fast

Hence, out of fear of introducing new exceptions by actually throwing one, beginning developers start writing code as:

public object getValue(string key){
  if(key == "CurrentUser")
    return SomeContext.User.Name;
  if(key == "CurrentTeam")
    return SomeContext.Team.Name;
  return "Not found";

Peaceful, right? No matter what value you ask for, no exception shall ever leave this method.

The unfortunate thing here if the calling logic is flawed somewhere, you might only find out much, much later in the process.
The above piece of code is called by some EmailTaskPreparer, which retrieves “current_user” to create an instance of a task. That task is put on a queue, one hour later a worker process picks it up and processes it by getting the current user’s email address, then sending an email.
One day later, you get a bug report there are undeliverable emails hanging around the system and you get to embark on the pleasant adventure of backtracking every possible piece of code that is sending emails, putting email-tasks on queues, and how they build those tasks.

The key lesson is: fail fast. If something is wrong, throw an exception on the spot instead of returning a peaceful default value.
The calling logic will still be just as flawed, but at least now you end up with a bug report stating that an InvalidKeyArgument was thrown when the EmailTaskPreparer called ‘getValue’, which will be easy to find, fix and will give you more time to actually get some real work done.

Don’t fail

Obviously, learning to code is all about understanding to take everything in moderation. The next rule of fist is to understand that exceptions are for ‘exceptional situations’ only.
When you have an abundance of exceptions being thrown all over your code, you’ll soon end up with a lot of try-catch blocks, and eventually you’ll end up with a code base that has two new problems:
– the code becomes less readable (at the bottom of your try block are a bunch of alternative code paths that make your logic harder to follow)
– the code becomes slower (the compiler can do less optimizations because it needs to make sure it can handle your expected exceptional code pathing)

To address the first, consider adding logic to your classes that can pre-approve an operation. This is why an iterator has a ‘hasNext()’ function, a command has a ‘canExecute()’ function: you can ask if you should expect something to go wrong, and decide on how to handle that on the spot, instead of 100’s of lines lower in a catch=block. It’ll make your code much more readable. Don’t fail if you could have avoided it.

Don’t worry

Finally, there are very little use cases to actually catch an exception. If you take the two previous rules in mind, exceptions will only occur when something really unexpected happens. In literature, exceptions are considered ‘final’ (the code below where you throw an exception will not execute) because they signify the system has entered a state from which recovery is not expected to be possible and execution should not continue.
Hence, if an exception occurs that you could not possibly have avoided and there’s no way you can recover from it, why bother catching it?
Don’t worry. Really, you should only really catch exceptions in a very limited couple of cases:
– you could not avoid it (no ‘hasNext’, ‘canExecute’, etc) but you still know how to recover from it For example: reschedule the task for later execution
– you want to hide exception details: a general catch-all block that catches any exception, logs it, and throws a new exception that hides any internals specific to the current layer of your application. For example you can should the SQL exception (“Connection failed for user “Bob” with password “Bob123″), only to throw a new generic DatabaseOperationFailedException.*
Beyond the above use cases and a couple of others, catching and handling exceptions should not be a part of the majority of your code base.

Don’t worry, all systems will fail at one point or the other, just try to make sure that when it fails, you’ll have a precise stacktrace and clean codebase to help you trace their cause (or, that you know how to plug a data center back in).

Understanding development prerequisites from a .NET perspective (NPM, JSPM, GULP, KARMA, WTH)

There is this awesome javascript framework called that I’ve been working on and using for a little while now. At a certain point, I feel you’ll owe it to yourself (*if not then at least you owe it to me *) to download one of the sample apps and play around a bit.

Some time ago, when I was trying to do just that, I felt overwhelmed at first. I had limited experience with javascript, HTML and CSS. Aurelia itself looked (is) really easy to grasp, especially since it has a very C# + XAMLesque feel to it. The learning curve still felt steep though, but only because of the surrounding open source stack: NPM, JSPM, GULP, KARMA and the likes. I was like WTH are all of these, and I wish I took 3 minutes to read an absolute beginners blog post like this one to bring my vocabulary up to speed.

Your system

There are some things you’ll need to setup on your system before making the switch to this (or any) open source project…


Git is a free and distributed version control system. In .NET speak: yes it is exactly the same as TFS but it’s totally different. Whenever you want to pull or clone a project (‘check out’) from a server (like github, you’ll need git so your OS understands what the hell pull or clone even means.
Additionally, you’ll often need to execute a command (more about that later). The normal cmd.exe or hipster mac OS alternative will at one point or the other drop the ball in understanding those commands, whereas installing git gives you a ‘git bash’ which looks and acts completely the same as your command prompt but understands how everything in this OSS stack fits together, better.


NodeJS is a platform based on Chrome’s javascript runtime. You could compare this to installing the .NET runtime on your system. To run your aurelia apps, users do not need to install NodeJS first, because your app will run in the browser and use that stack. However, when you are developing apps, you do need a runtime for your tooling to execute in. And that runtime, will be NodeJS.


You’ll also need an IDE. Your IDE should be an integrated bundle that can do three things: manage your project, execute commands and help you write code.

Unfortunately, Visual Studio ultimate super duper bundle, fails the third requirement as it does not (yet) support ES6 syntax. I know! What a shocker right!

My first alternative was going back to a simple text editor. According to stackoverflow’s 2015 survey, SublimeText is the second favorite one. Once set up with an ES6 plugin for next generation javascript syntax highlighting and intellisense and an integrated terminal/command prompt I realized going back to a text editor was the exact opposite of taking a step back. It’s really, really, really fast. Like: really fast!

A little later, we received a free OSS license for JetBrain’s WebStorm IDE. One of the biggest, noteworthy advantages for me was the integrated (visual) support for git&github. After using it for about 2 months now, it has my love, my official seal of approval, and I doubt I’ll go back to VS for javascript development…

Package managers

Managers… Plural.


NPM is a javascript package manager. In aurelia, we use NPM because of it’s ability not only to install packages in your project, but also in your tooling. Think of it as Visual Studio’s “plugins”, only you install the plugins in your build process/tooling instead of your IDE.


JSPM is also a javascript package manager. In aurelia, we use JSPM because of it’s ability to manage dependencies not only in your project but also in your app while it’s running. Suppose your project uses package A and B. Both A and B have a dependency on package C, but they depend on a different major version: A uses C1 and B uses C2. Whoa, now what? Actually, JSPM will download both version 1 and 2 of C, then when you run your project it will load both C1 and C2 in a different ‘scope’. If some component in A needs something of C, it’ll get the C1 version, whereas a component in B will get the C2 version. WHOA! Think of it as a (really) advanced Nuget.

NPM Libraries

Remember: NPM is used to install tooling, so these libraries are your development tools.


Using NPM, you can install Gulp. Gulp runs automated development tasks. gulp watch for example, is the equivalent of your Visual Studio’s F5. It will run several automation tasks like cleaning the code, building it, starting a NodeJS server (like VS starts an IISExpress) and serve up your website (the actual watch part). While you are developing, you can keep the gulp watch command running and any change you do in your code will trigger the complete clean, build & run task chain (in about 0.3 secs) so that your website is automatically refreshed and you can see your changes.

Wait: build? Is javascript built? Javascript itself is not built but it’s a scripting language that’s executed by the browser’s javascript runtime. However, you’ll often use a superset of Javascript (like TypeScript, Dart, … The aurelia team just code in ES6/ES7 (the next and next-next javascript spec)). Because your browser does not understand those, your TS/Dart/ES6 is compiled down (called ‘transpiled’) to plain vanilla javascript that works in any browser.

We use gulp for a number of tasks including building documentation, releasing, etc as well.


Karma is your test runner. It performs a number of tasks to build the code (like gulp), scan a directory for all test cases and run them lightning fast. Just like gulp watch, you can trigger your test runner with karma start and keep the command running. Any code change will trigger a rerun of affected tests (again: wow) so you can instantly check what you’re breaking/fixing. (More breaking than fixing in my case, but whatev)

Time to play

Armed with this knowledge, I hope you find it easier to go play with an aurelia sample. Set up git and NodeJS from the System chapter, then launch a git bash. Navigate to a working folder:

cd .. #go up one directory, or
cd someFolderName # go into a directory

Now, execute

git clone

This will clone (download) the contents of the a sample app into a folder called app-contacts. When done, navigate to that folder

cd app-contacts

Armed with the knowledge in this article, you should now be able to follow this little guide, and have the app running locally without screaming WTH once. ūüėČ

John Holmes and the case of the mysteriously missing LightSwitch record

Chapter one: the night of disappearance

The cold wind was howling in the streets when Holmes knocked on Elvis’ door.¬† “It just doesn’t make sense”, was the first thing Elvis said, “it’s simply… gone”…

Aight, pause please. I’m enjoying high 80s (Fahrenheit) at the moment here in the Caribbean, there was no door (just skype) and Elvis is not the actual name of the developer I was helping. I’ll try fiction again in a couple of years, let’s just get through the story of this missing LightSwitch record I encountered last week because I’m pretty sure one day, someone is going to stumble upon a similar issue and this blog post will save him/her half an hour of being dumbfounded…

Chapter one: (for real this time): a record went missing

So here’s what really happened: Elvis called me up because the LightSwitch desktop application that he was working on was throwing an unexplainable nullpointer exception. Unexplainable, because his flow was really basic, textbook easy even:

a) create a record from a “create new entity” screen (the entity was called a “case”)

b) when the screen has successfully saved the new record, use code to close the “create new entity” screen and open the default detail screen for that case enity

c) a nullpointer exception happens in the _initializeDataWorkspace method on this.Case

I’d never seen this before. Right after successfully saving, we show a detail screen on the same entity and the entity just disappears. I’m pretty sure at that point I spent at least 10 minutes of mumbling “I’m dumbfounded“. We started debugging and piece by piece we were able to reassemble the complete puzzle…

See, each screen in a LightSwitch desktop application has its own DataWorkspace.¬† This is LightSwitch’ implementation of the unit-of-work pattern, whatever changes happen in one screen get committed as a whole upon saving, and either all changes are persisted to the data source or, in the case of an exception, none.

Since each screen has it’s own DataWorkspace, a single entity can exist multiple times (multiple instances) in different DataWorkspaces.¬† This also means that, unlike the LS HTML client, when you type code like


the framework will actually take this.Case, an entity which belongs to the DataWorkspace of the “Create new entity” screen,¬† and pass only the ID field(s) to the new “Detail” screen.¬† The new screen will then actually use the ID(s) to retrieve the entity again, this time in its own DataWorkspace.

Chapter 2: the resource segment cannot be found

Sure enough, Fiddler soon revealed that when the second screen tried to retrieve the entity again, something went wrong.

Really wrong.

The exception returned was something along the lines of “the resource segment cannot be found for ‘http://localhost:xxxx/ApplicationData.svc/Case'”

Another ten minutes of mumbling about how dumbfounded I was, went by, before we got an Epiphany…

LightSwitch uses the OData protocol to interact with the server tier. OData uses http verbs (GET, POST, etc) for the ‘action’ (***), and a URI to state which entity you want to do your action on. URI is the keyword here: unique resource identifier. Or translated into normal language: your call to “blah blah blah.ApplicationData.svc/case/123” means you want me to retrieve the ‘Case’ entities and return the slice identified by “123”.

Get all resources for “Case” and only return slice (fragment) 123.

So basically this was the “OData way” of saying: case 123 can’t be found.

Thanks for being straightforward and all…

But… we just created it. And according to our select * from Case, the record is in the database, then why could LightSwitch not find it?

Chapter 3: if it looks like a duck

The mystery continued with 10 more minutes of mumbling about dumbfoundedness… But then we remembered that there’s actually a filter active.

LightSwitch supports row-level filtering, ideal for slicing your records in multi-tenant or advanced security/permission situations.

And sure enough, this was the case

  query = query.Where( case => case.AssignedCategory.Name != "Family");

The user we were testing with did not have the FamilyLaw permission any more, effectively causing all cases to be filtered to only show the ones where the assigned category is not “Family”.



Turns out, our problem was even a little more subtle…

This LINQ query filters out all the cases that have an AssignedCategory that is not “Family”.

Read that again… The linq query is actually, unintentionally I assure you, adding two filter criteria behind the scenes:

  case.AssignedCategory != "Family"
  seems to be interpreted as...
  case.AssignedCategory != null && case.AssignedCategory.Name != "Family"

Really, LINQ? Really?

Once we rewrote the LINQ query (to allow cases with AssignedCategory == null), our freshly created case entity (which has not yet been assigned to any category) now found its way down to the details screen.


*** PS: LightSwitch doesn’t really use HTTP verbs like (PUT, PATCH, …) directly on the OData service.¬† Because each screen has it’s own “unit of work”, all changes get posted just once, together, to an URI called $batch.¬† This HTTP “batch” call actually contains all different changes that happened in a screen (delete this, modify that, etc) in a single HTTP call.¬† Using transactional techniques, all changes then all get persisted in the data source together or, in the case something goes wrong, none of them get persisted.

Meet the new love of my life, her name is

YEZZZZ! I can finally start spreading the love of the goodness that is named Aurelia, with which¬†I’ve secretly been in love with for a while¬†now. I meant to write about her last week, but an NDA contract prevented me from bragging about her beauty before Rob did.

Wait, who’s rob? Who’s Aurelia? What does this have to do with anything? How does it affect me? And you?


Rob Eisenberg’s one of the most genius architects of our era. I’ve been a fan of his work since the Caliburn days, a framework he wrote which made MVVM for WPF/SL/WP/… as easy as possible by reducing boilerplate code and using conventions instead. ¬†Over the last couple of years, Rob created an HTML/JS framework named DurandalJS, a masterpiece which never got the credit it deserved. ¬†Well, except from the fine folks at Google, who hired Rob to help build out the next generation of their popular AngularJS framework.

Late 2014 however, Rob left Google because¬†his colleagues were not as visionary as he was (my words, he was more diplomatic in his goodbye message) and started assembling a team of world-renowned experts (and me) to focus on the first of the next-generation javascript frameworks…


So ok, enough about my man-crush on Rob and his hyperthreaded brain, let’s focus on this beauty of this open-source¬†framework that’s called aurelia. Why would this framework be any better than it’s “competitors”, like EmberJS or the next AngularJS?

I could copy¬†its¬†major strengths from the homepage, ¬†but I’d rather highlight three really important ones (which is not to say you shouldn’t head over to right now to look at her in her full glory):

  1. ES6. If clarification is needed: ES6 is short for EcmaScript 6, the next generation of javascript. It’s just a (finished) specification at this point, since none of the major browsers actually fully support ES6 yet, so aurelia is written in ES6 but then ‘compiled’ into current javascript (ES5). ¬†In the gitter channel, an open chat channel where you are all welcome to discuss anything aurelia, I’ve seen Rob look at the next-next HTML (thus: HTML7) specs, to analyse how we should build the best (most future-compatible) API’s. Long story short: Aurelia is ready for the future, today.
  2. MV* architecture with conventions. Lots and lots of conventions. Aurelia assumes a ton of things out-of-the box, and you can add your own conventions. Got a VM named customer.js and a V called customer.html? Aurelia saw¬†what you were trying to do there. It wasn’t that hard to get either, so why should developers have to write code/configuration to bind those two together? Write code only once and especially: avoid writing unnecessary code (and yes if you don’t like a convention you can always override it). Which seamlessly brings us to the next highlight:
  3. Extensible HTML…¬†As a technology enthusiast, I get a nerdgasm just looking at aurelia. However if one must build large LOB applications, writing HTML all day is too granular to make any kind of progress. However, thanks to aurelia’s extensible HTML compiler, things like <barChart xAxis.bind=”months” yAxis.bind=”sales” />¬†all the sudden, become valid HTML.


Think about that for a moment…

This means that me and you and anyone can write reusable building blocks which are an abstraction level higher than HTML, without actually hiding/losing control over the underlying technology stack!

Me? You?

You and me shared a love for RAD,that’s for sure. And Aurelia is not RAD at all and certainly not a better version of anything like LightSwitch.


Aurelia is only the tip of the arrow currently loaded on my bow.

Late last year, three of my LightSwitch customers (and two more are in discussing phase) and I actively started looking at a newer tech stack to phase out LightSwitch if the day would ever come LS¬†is announced ‘dead’.

We looked at so many RAD frameworks and were impressed by a quite a few, but convinced by none. Most RAD frameworks work great for small and simple CRUD apps, but suffer from either poor testability, modularity, scalability, extensibility, most likely all of the above.

Hence, we’re currently building out a super-framework ourselves based on Entity Framework, Web API (CQRS architecture) and aurelia. I use the term super, not only because it is super and kicks ass, but mostly because the intent of our venture is to take all boilerplate and repetitiveness out, and build out applications using a ‘higher abstraction of code’. A super-set of traditional code. Much like LightSwitch used graphical designers as a higher abstraction of all the code goodness it generated “under the hood”, however this time we’ll still have full control of what’s on top of the hood, “under the hood”, and the hood itself.

This’ll keep me very busy during the first part of 2015 (during which I still have LightSwitch projects and will share whenever I can share any LS goodies), then afterwards will undoubtedly be a large part of my future for quite some years to come. Perhaps your future too, as it’ll all be open for your LOB app development pleasures. If you’re in a position where you need a modern, open and future-proof stack for business app development now, please do get in contact so we can work together asap, or at least let me know¬†about your special requirements so I can make sure we can develop this thing as smart as possible.

The future starts today. I haven’t been so excited about tech since a few years ago and am really happy to be a part of, from the start of, this beauty. ¬†Aurelia really is the first of a next generation of frameworks, you owe it to your future self to take her out for a spin. If not today, then tomorrow.

If she looks too high-tech or too granular for you or to make LOB apps today, give it a little bit of time too. We’re at the start of this journey and I’ll put in the effort to make sure she’s worth the venture!


So what’s the deal with that announcement?!?

I wish I could tell you. No seriously, I deeply apologize for the extreme hopes my last post left, but I’d be breaking my NDA if I’d talk of this before the official announcement, which was planned for today but apparently needs a little more preparation before it’ll take public form.

Perhaps, no surely, I shouldn’t have put a specific time-frame in my last post.

I hope tomorrow, or later this week, I can undo this disappointment of this post and wash off the smell of rotten tomatoes, that you may now rightfully throw at me, by sharing the goodness that is this novelty with you!!

It’s 2015, and LightSwitch is dead… Now what?

In case I haven’t seen you yet this year (and chances of that are high since I spent almost all of my time in my hammock so far), happy new year to you!

Just two weeks ago, the year turned 2015, always a great opportunity to reflect upon the past, and to learn lessons for the future.

And what a harsh lesson 2014 has taught us: LightSwitch is dead.

There, it’s out, and apparently I’m the first one to publicly carve these words in cyberspace. But unfortunately, a rose by any other name is still a rose, so let’s just call it what it is: dead.

Stage 1: denial

Let me first shed some light on why I consider the lightswitch to be in eternal off-state: there have been no new substantial developments since the HTML client (you weren’t really sitting around waiting for the O365 stuff now, were you), the ‘team blog‘ hasn’t had any meaningful posts in over half a year and many of the active community bloggers have either changed blogs, or have only been writing about using LightSwitch in combination with other technologies (with most of the focus on the other technologies).

If you want to try denying a technology being dead simply due to lack of evolution, then here’s a quote from the team latest post:

we’re currently planning to actively engage with the community and start our discussions on the roadmap in the middle of next year

Our love is dead, and you have been feeling it for a while now.

Perhaps you haven’t admitted it to yourself. Perhaps you are still in denial, but in this fast-paced world of ever-evolving technologies and agile methodologies, I cannot consider the product of a team that shifts priorities for over a year as the solid foundation for my own work.

Stage 2: anger

If you want to, please do take a quick break from reading now to go to the gym, box club, or whatever else you usually do to vent your anger. If you happen to have any pitchforks and/or torches, you could even¬†join the rest of us in our march in the MSDN forums too, there’s a lot of anger already shared¬†over there.

Stage 3: bargaining

We’re still reflecting the pain of¬†2014.¬†Those of us who were able to overcome denial and anger stages, started bargaining. End of September,¬†I’ve personally sat down with Microsoft folks¬†to talk about the idea of how providing limited extension points so the community would allow us to¬†create a toolkit¬†to address a lot of the missing features.¬†Others have publicly pled to open-source the entire stack, which would fit in great with MSFT’s latest vision and announcements¬†about open-sourcing¬†parts of their stack. ¬†Some have threatened to mail Mary Jo Foley, others to mail Somasegar, in a passive-aggressive attempt to bargain or even blackmail¬†the team into action.

Unfortunately, none of that led to change.

Stage 5: Acceptance

You skipped stage 4: depression.

You just scrolled up and noticed I did not write about stage 4: depression.

Stage 4 in the Kubler-Ross model (‘the five stages of grief’) describes the emotions of sadness, fear and uncertainty that start to develop during the earlier stages. ¬†Feeling these emotions is natural, personal, and shows that we are slowly entering the final stage: acceptance. ¬† So let’s cut to the point and discuss what acceptance could bring, for me and my relationship with you, my highly valued readers, and you’ll see there is very little sadness to be found.

  • LightSwitch being dead does not mean it does not have a future. At some point, probably end 2015 or early 2016, we’ll see a next version from the same MSFT team. Personally I don’t think they’ll actually revive LightSwitch as some kind of frankenstein monster with new body parts, but instead reuse only their experience can into a new product¬†with a new name and marketing strategy.
  • LightSwitch being dead does not mean it ceases to be important in 2015. Personally I have a ton of ongoing projects and consulting opportunities, and they all still stand valid. LightSwitch has always been a tool to create CRUD-oriented, small to medium sized applications, and that is still true regardless of the evolution¬†of the platform itself. ¬†If LightSwitch is the right answer to a particular problem, then File>New>LightSwitch Application here I come!¬†Or as the team puts it:

If the support we have in Visual Studio 2015 meets the needs of your application, then you should feel confident in developing with LightSwitch or Cloud Business Apps as we build out the roadmap

  • This implies an ongoing commitment to my own blog as well. I’ve always blogged strictly about my own professional experiences, and if I encounter anything worth sharing and I find the time to do so, I will gladly blog it! Being it about LightSwitch, or something else…

So there’s the big cliffhanger… What something else?

What now?

There’s not much presently existing that can match the development speed of LightSwitch. However, because LightSwitch does not offer modularity, has bad testability and¬†devastating performance for medium to large applications, I’ve been looking for alternatives to answer challenges that¬†LightSwitch can not…

And I have found it too.

I have found my sweetspot combination of a technology stack that is completely open source (no longer dependent on MSFT management decisions), highly scalable, highly modular, highly performant, fully customizable but yet offers incredible speed of development.

“No way”, I hear you say, “Such a thing does not exist! If it existed, I would have surely heard about it”.

And you are right in saying so. Such a thing does not publicly exists… Yet. But so far, I’ve been mainly writing about 2014, and 2015 is still so very young. This coming Monday, in an announcement that is not my own, the first tip of this veil of secrecy that holds¬†my future, and perhaps yours, will be lifted…