Note: the last time I did even an off the cuff review of a Microsoft application, the whole CAB argument was born. I am writing this statement before looking at the code, mind you, so I have no idea what the review will be.
For a change, let us start by talking about the documentation, which I am reading while the code is downloading.
Multi-Tenant Data Architecture is a very interesting read, I agree to most of what they are saying there, just not with the way they are pushing things and the conclusions they are trying to draw. In particular, we have this graph, showing the economic difference between shared vs. isolated approaches.
I have no idea where they go that data from, or what it is based on. From what I have seen, it is more like this:
And I didn't include a whole bunch of stuff that makes shared approach a really bad idea, like the required security audits, risks on data dependencies in shared data, etc.
On to the application itself. This time, I started from the UI, moving inward. In the BasePage, the master page is set according to the tenant alias. There is also the tenant id, but it is very rarely used.
Item of interest, ISitkaSoapService, which is a WCF service that is used for such things as CRUD, will happily accept SQL from the user. I'll not even try to talk about the validations that they have there, accepting SQL from the client is a mistake unless you are an DB Server. And that is at the architecture level.
I went a little bit deeper, but at some point (around 03:30 AM) I decided that I am not getting to get anything new from this, and there isn't much of a point in posting a code review for that.
Oh, and just to make things more interesting, LitwareHR is not a multi tenant application by my definition. It is an application that can handle data from several clients, and it have skinning, but that about it. Yes, it has the idea of tacking fields to an entity, that is about as close as it gets to what I would consider multi tenancy.
What it is, in my eyes, is just a normal application, with a need for dynamic fields, that is. Show me different behavior across tenants, different entities. And by that I don't mean just Customer + Comtoso.FriendlyName, I am talking about something that actually does something with the extra data, rather than just display it.
Note: After reading this post, I had seriously considered not publishing it, see the CAB episode for reference on why. I decided to publish it anyway, see CAB episode for why.