Environment Variables
Dynamics 365 / Power Apps solution can have Environment Variables. Often a Settings table (=entity) would be created to store configuration settings that differ between environments. We now can replace these with environment variables.
These environment variables can be added to a solution, be exported, and imported in another environment. If you do it correctly it even asks for the values for the environment variables when you import.
They can have distinct types, but the simplest one is Text. Other options are Decimal number, Two options and JSON. JSON is the most flexible one because you can store multiple settings, so you don’t need to create an environment variable for each one. It is also future proof because you can add more settings later.
There are also two more advanced data types, Data source and Secret (preview) which make it possible to store the values outside of Dataverse. With Data source you need to add a connector and Secret values are stored in Azure Key Vault.
The variables are stored in the tables environmentvariabledefinition and environmentvariablevalue, which can be secured using Dataverse Users and Roles.
You can use these environment variables in Client-side code (JavaScript), Plugins and in Power Automate but there is no out-of-the-box way to retrieve them. You need to query the tables to get the values.
Retrieving Environment Variables
So, there is not a straightforward way to retrieve them in plugins. Therefore, I added a method to my base plugin class to get the variables in a dictionary. You can also add this code in your specific plugin, instead of your base plugin.
I have added the methode GetEnvironmentVariables
which will retrieve all the environment variables in the environment with the Current Values. It will pick the first Current Value if there are more than one. If there are no Current Values, then it will retrieve the Default Value. I don’t check for the status (active/Inactive), but this can be added easily if needed.
It does this by querying the table environmentvariabledefinition, which contains the name, type and default value. The current values are stored in a separated table named environmentvariablevalue. The code assumes the values are of the data type Text. I haven’t tested this code with other data types yet, but I assume JSON will also work.
The environment variables are retrieved on every execution of a plugin, so I have added a temporary cache which helps when the plugin is run multiple times under high load.
public class Plugin : IPlugin
{
static IReadOnlyDictionary<string, string> EnvVariables;
static readonly object Lock = new();
protected static IReadOnlyDictionary<string, string> GetEnvironmentVariables(LocalPluginContext ctx)
{
ctx.Trace($"Entered GetEnvironmentVariables");
// Singleton pattern to load environment variables less
if (EnvVariables == null)
{
lock (Lock)
{
if (EnvVariables == null)
{
ctx.Trace($"Load environment variables");
var envVariables = new Dictionary<string, string>();
var query = new QueryExpression("environmentvariabledefinition")
{
ColumnSet = new ColumnSet("statecode", "defaultvalue", "valueschema",
"schemaname", "environmentvariabledefinitionid", "type"),
LinkEntities =
{
new LinkEntity
{
JoinOperator = JoinOperator.LeftOuter,
LinkFromEntityName = "environmentvariabledefinition",
LinkFromAttributeName = "environmentvariabledefinitionid",
LinkToEntityName = "environmentvariablevalue",
LinkToAttributeName = "environmentvariabledefinitionid",
Columns = new ColumnSet("statecode", "value", "environmentvariablevalueid"),
EntityAlias = "v"
}
}
};
var results = ctx.SystemUserService.RetrieveMultiple(query);
if (results?.Entities.Count > 0)
{
foreach (var entity in results.Entities)
{
var schemaName = entity.GetAttributeValue<string>("schemaname");
var value = entity.GetAttributeValue<AliasedValue>("v.value")?.Value?.ToString();
var defaultValue = entity.GetAttributeValue<string>("defaultvalue");
ctx.Trace($"- schemaName:{schemaName}, value:{value}, defaultValue:{defaultValue}");
if (schemaName != null && !envVariables.ContainsKey(schemaName))
envVariables.Add(schemaName, string.IsNullOrEmpty(value) ? defaultValue : value);
}
}
EnvVariables = envVariables;
}
}
}
ctx.Trace($"Exiting GetEnvironmentVariables");
return EnvVariables;
}
// Other code of the base Plugin...
}
How to use it in your plugins?
If you added the code above to your base plugin (or your specific plugin), you should be able to use the method GetEnvironmentVariables
which will return a Dictionary
with all the environment variables and their values in the environment.
You can then use the Dictionary
to lookup the variable you need. See the example below:
ctx.Trace($"Try getting av_myvariable from environment variables");
if (!GetEnvironmentVariables(ctx).TryGetValue("av_myvariable", out string myVariable))
throw new Exception("Couldn't read environmentvariable av_myvariable!");