Consider the following use cases:
SaaSGrid's built-in Tenant and Provider Contexts', in conjunction with a concept called "impersonation", provides a mechanism that can be used to access data for any and all tenants of an application. This article will discuss how this can be done and presents a basic example that involves modifying the existing Taskr sample application.
Introduction to the Tenant and Provider Context
Before getting started, let's review and compare the Tenant and Provider Context:
Tenant Context
Provider Context
Note: In addition to the Tenant and Provider Contexts', there is also Session, Request, User, and Subscription Contexts' that will not be discussed further here but may be helpful when developing your application. Please consult the SaaSGrid Developer Guide for additional information.
Using the Provider Context to Get Application Data
All database queries done within an instance of the Provider Context apply to all of an application's data. See the code snippet below to see an example of creating and using the provider context.
Sample Provider Context Usage using (ProviderContext providerContext =
ProviderContext.NewProviderContext())
{
// Data queries here execute for all application
// data - not just the current user's tenant.
}
"Wrapping" database calls as shown above is essentially all that is required to do basic operations that pertain to all data in the system. This approach does have some limitations pertaining to data retrieval:
In the next section, we'll take a look at another approach that allows you to retrieve data while knowing which tenant created it. This is enabled with a concept called "context impersonation."
Context Impersonation
It is possible to nest the Tenant and Provider Contexts within one another to affect the scope of a command being executed, much like the stack available within a traditional programming language. The diagram below shows how the scope of commands are changed as the application developer manually instantiates various Tenant and Provider contexts.
The following code example shows how to use context impersonation to perform data retrieval for all of a provider's data while having access to information about the tenant that created it.
Sample Context Impersonation using (ProviderContext providerContext =
IList<ITenantProfile> customers =
providerContext.GetCustomers();
foreach (var customer in customers)
using (TenantContext tenantContext =
TenantContext.NewTenantContext(customer.ID))
// Data queries here execute for the
// designated tenant. You can link
// the tenant information to the data this way.
Warning: This specific code example could take a very long time if your application has many customers. You'll probably want to consider calling code that loops through every tenant sparingly due to the performance implications.
Please also note that we are cognizant of the anticipated need to include tenant data, or some means of linking rows with tenant information, for data returned from queries executed in a provider context. We're looking to include this in a future release of SaaSGrid, thus eliminating the need to loop through each tenant.
Live Example
We produced an additional sample that demonstrates usage of the Provider and Tenant Context. We took the "Taskr with Linq" example, and added an additional view beneath the task list showing all of the tasks from other companies, as depicted in the screenshot below.
An additional method on the Taskr Core service was implemented to return the data for this grid, whose code is shown below. As you can see, this loops through each and every tenant and builds the list of tasks that should be displayed on the grid.
Taskr Service Addition Guid myTenantId = TenantContext.Current.GetCompanyProfile().Id;
IList<TaskFromOtherDTO> tasks = new List<TaskFromOtherDTO>();
using (ProviderContext providerContext =
IList<ITenantProfile> customers = providerContext.GetCustomers();
if (!customer.Id.Equals(myTenantId))
TenantContext.NewTenantContext(customer.Id))
TaskrDataContext db = new TaskrDataContext(
ConfigurationProvider.GetConnection("Taskr"));
foreach (var task in db.Tasks.OrderBy(t => t.DueDate))
tasks.Add(TaskFromOtherDTO.StaticMapFrom(
task, customer.Name));
return tasks;
You can download the full sample of this special Taskr version from our download area by clicking here.
Of course, as always, please post a comment to this article or post in our developer center if you have any questions or feedback.
It has been noted that this solution will only work if the Tenant Portal application's database is housed on one database (which is typically the case anyway). This is correct as the Provider Context has limited support at this time. (Data operations done with the Provider Context operate correctly on single database, co-mingled applications only at this time.)