I’ve done some posts about multi-tenancy and BCS lately, but haven’t combined the two. So todays topic (and no, it’s not a joke…) will be BCS in a multi tenant environment. Mainly because you have some choices to make and I want to provide you with some input on which you might be able to make the right one
Ok. So you’re setting up a multitenant environment in which you want to utilize BCS. When you follow the SharePoint 2010 for Hosters whitepaper, you will find yourself setting up a BCS service application in Partitioned mode. This basically means every tenant in your environment get’s it’s own little space inside of the BCS service application. The management pages in Central Administration are unavailable, instead you have to setup the Tenant Administration page on which the tenant may manage their BCS models and permissions, much like you would do from Central Administration.
This is a good approach when you’re tenants don’t have anything to do with each other. They can all upload their own BCS models and use them in their SharePoint sites. There are some limitations though, the biggest one (in my case) being that you cannot use .NET assembly type models. So when you (or your client) requires such a BCS model, setting up the BCS service application in partitioned mode simply isn’t an option.
Right, back to my own environment. What we are trying to acheive is offering our customers a ready made product, in which BCS is a part of the solution. Basically, the solution consists of a client side sync program which takes data from an ERP environment and syncs that to a centrally hosted database. The data in that database is available in SharePoint through BCS. Setting up a new customer should be as simple as running an installation script which creates a new tenant (site subscription), creates some sites and stuff like that. So we had a few design questions to answer here:
- Are we going to use seperate databases for each tenant?
- Are we going to use seperate BCS models for each tenant?
- How can we provide security?
- Which type of BCS model are we going to use?
Based on the approach SharePoint uses itself, I decided to go with a multi tenant, partitioned approach. So we created a single database which will hold data for multiple tenants. Each record in each table therefore has a column ‘TenantId’ which identifies to which tenant the record belongs.
So what about BCS? Well since the database is the same for each tenant, it would be rather useless to create a seperate model for each tenant; they’d all be the same. But when using a single model, we need to think about security. Of course the first thing which springs to mind is entity filters. It’s quite easy to provide filters for your BCS methods. You could create a tenantId filter and provide a value for it to make sure the right records are being shown. The major problem with that approach is that the filters can be setup and adjusted by your site owners. Now when using GUIDs as tenant Id’s, one might argue that you’ll never simply guess another tenants id. Maybe that’s true, but still; if you’re able to find out a valid id somehow; that’s a big security risk.
So that’s out of the question. What about a webservice? Kind of the same problem. The webservice won’t have SharePoint context and thus you don’t know where the request for data is coming from. And if you don’t know that; how would you filter the data? I didn’t find a viable solution for that problem, so webservices was out too.
People who visit my blog more frequently might remember the article I wrote quite some time ago: Creating secured BCS objects with BCS Meta Man. I described a way to use .NET assembly BCS models to provide filtered data, based on the context of the BCS list. That approach still works fine, so I decided to use it again for my multitenant challenge.
One problem though. As described above; you cannot use a .NET assembly model in a partitioned BCS service application. But hey, no one says you cannot use a non-partitioned BCS application from a site subscription site, right? So that’s exactly what we’ll do. The basic steps are:
- Setup a normal BCS service application (Central Administration -> Service Applications)
- Use tenant proxy groups to map this service application to the tenants you want to provide with your common BCS model
- Create a new .NET assembly based BCS model
- Use the SPContext to filter the results in your BCS .NET code. For instance, you can use SPSite.SiteSubscription.Id and use that GUID as a tenantId in your multitenant database (that’s the approach I used). See the linked blogpost above for an example on how to do that.
- Add the model to your BCS service application
- Create an external list in two seperate site subscriptions. Make sure the filter works as expected
That’s it! You know have a global BCS model which is available for every site in a web application linked to the global BCS service application. The filtering being done in the .NET assembly makes sure that a tenant won’t ever see any data it shouldn’t. You can even extend the filtering and use property bag configuration data to provide some more filtering based on a subsite for instance.
The pro’s: you only have to manage one database schema, one model and one service application. And your tenants won’t be able to configure it, so security is good. The con’s: this only applies when all tenants use the same model. If you want more flexibility, this approach won’t be a good choice. But since you do have freedom over what a site actually shows (the views you configure for your external lists for instance), your customer will still perceive a customizable solution.