One major consideration you have to make when building an enterprise layer is the flexibility of the component library itself. The components and functions provided by your enterprise layer have to be created in a tenant-agnostic way. This means that they should not understand the tenant layer (aka project layer in Helix terms) or which website may be using them. They simply exist to serve the tenants.
One easy trick that I’ve been using across many of my projects is allowing for the generic Enterprise components to allow for a configuration fallback.
Configuration Fallback
Let me explain. The idea is simple. At the enterprise layer, I want to provide a default configuration value that may be stored in a configuration file. Let’s assume this configuration value is for an API Key for the FooBar service:
<sitecore> <settings> <setting name="FooBar.ApiKey" value="XYZ" /> </settings> </sitecore>
Given that we’ve set this up, we can write code like this to extract it:
var setting = Sitecore.Configuration.Settings.GetSetting("FooBar.ApiKey"); // setting is "XYZ"
So, assuming that I’m making a generic component that uses this API Key, how can I handle this configuration setting being a different value per-tenant?
The solution is Configuration Fallback.
To pull this off, it’s quite simple. I will introduce configuration that looks like this:
<sitecore> <settings> <setting name="AcmeCo.Alpha.FooBar.ApiKey" value="ABC" patch:source="Project.Alpha.config" /> <setting name="AcmeCo.Gamma.FooBar.ApiKey" value="123" patch:source="Project.Gamma.config" /> <setting name="AcmeCo.Enterprise.FooBar.ApiKey" value="XYZ" patch:Source="Foundation.FooBar.config" /> </settings> </sitecore>
Notice that the Alpha and Gamma sites have introduced a custom setting, while the Enterprise layer provides a default setting from Foundation.FooBar.config. All settings files are named intelligently to help with quick debugging when glancing at /sitecore/admin/showconfig.aspx.
To implement the configuration fallback, I introduce a service that all layers can utilize:
namespace Enterprise.Configuration.Services { public interface IConfigurationManager { string GetSetting(string settingName); } public class ConfigurationManager : IConfigurationManager { public string GetSetting(string settingName) { var organization = "AcmeCo"; // replace with your convention as necessary var siteName = Sitecore.Context.Site?.Name; if (siteName != null) { var localSetting = Sitecore.Configuration.Settings.GetSetting($"{organization}.{siteName}.{settingName}"); if (localSetting != null) return localSetting; } var enterpriseSetting = Sitecore.Configuration.Settings.GetSetting($"{organization}.Enterprise.{settingName}"); if (enterpriseSetting != null) return enterpriseSetting; return Sitecore.Configuration.Settings.GetSetting(settingName); } } }
Which results in this:
var configManager = new ConfigurationManager(); // we'll cover injecting dependencies next // Assuming that Sitecore.Context.Site is Alpha: var setting = configManager.GetSetting("FooBar.ApiKey"); // resolves to "ABC" // Assuming that Sitecore.Context.Site is Gamma: var setting = configManager.GetSetting("FooBar.ApiKey"); // resolves to "123" // For any site that doesn't explicitly call out this config value: var setting = configManager.GetSetting("FooBar.ApiKey"); // resolves to "XYZ" as the 'enterprise default'
In doing this, I’ve now created a foundational element that all components can use. Remember: your Enterprise components should not have any logic directly related to a tenant website. Instead, you can utilize configuration injection techniques to resolve dependencies and settings at runtime!
Bonus
You can also attach settings to your site definition and fallback to this if you choose.
For instance, assuming that my site definition looks like this:
<sitecore> <sites> <site name="Alpha" ... FooBar.ApiKey="ABC" /> </sites> </sitecore>
I can then extract this configuration via this code:
var setting = Sitecore.Context.Site.Properties["FooBar.ApiKey"];
Happy coding!