Advanced Orchard: accessing other tenants' services
Many using Orchard's multi-tenancy feature sooner or later want to share data between tenants or generally, execute some operations on other tenants from one tenant. This is possible! Let's see how.
First some core Orchard fundamentals: Orchard creates so called shells for tenants. These shells describe that sub-application what a tenant is, among others the shell also has its own Autofac IoC container. This container deals with all the dependencies that are injected or otherwise requested. The interesting thing is that you can access the shell - the shell context - of all running tenants and through it also their IoC container. Now if you have the container you can make dependency resolution calls on it - what means that you can resolve services from that shell, i.e. that tenant.
public class TenantAccessDemo
{
// ShellSettingsManager lets you access the shell settings of all the tenants.
private readonly IShellSettingsManager _shellSettingsManager;
// OrchardHost is the very core Orchard service running the environment.
private readonly IOrchardHost _orchardHost;
public TenantAccessDemo(IShellSettingsManager shellSettingsManager, IOrchardHost orchardHost)
{
_shellSettingsManager = shellSettingsManager;
_orchardHost = orchardHost;
}
public void UseServicesFromTenant()
{
// Fetching the shell settings for a tenant. This is more efficient if you have many tenants with the Lombiq Hosting Suite,
// see below.
var tenantShellSettings = _shellSettingsManager.LoadSettings().Where(settings => settings.Name == "TenantName").Single();
var shellContext = _orchardHost.GetShellContext(tenantShellSettings);
// Creating a new work context to run our code. Resolve() needs using Autofac;
using (var wc = shellContext.LifetimeScope.Resolve<IWorkContextAccessor>().CreateWorkContextScope())
{
// You can resolve services from the tenant that you would normally inject through the constructor.
var tenantSiteName = wc.Resolve<ISiteService>().GetSiteSettings().SiteName;
// ...
}
}
}
If you're operating a multi-tenant environment you may also want to look at the Lombiq Hosting Suite: among others it has a Maintenance feature that you can use to run code in the context of tenants in a safe and scheduled way. Also it has an extended ShellSettingsManager that stores shell settings in the database: this means you can have any number of tenants, you can even fetch their settings by name or you can page when listing them and you don't have to take care about all the Settings.txt files in App_Data.