web
You’re offline. This is a read only version of the page.
close
Skip to main content

Notifications

Announcements

No record found.

Community site session details

Community site session details

Session Id :
Dynamics 365 Community / Blogs / Dynamics CRM Tools / Use feature flags in your p...

Use feature flags in your plugins

Tanguy TOUZARD Profile Picture Tanguy TOUZARD 687 Most Valuable Professional
Lately, there was a discussion on Twitter about the best practice to handle plugins: One class per plugin? One project per plugin? or anything else? On my side, I'm using one project for all the plugins for the same customer. This is what I answered on Twitter. Then came a question : How do I handle the fact that some plugins may have not been tested or completed yet and I need to release the plugins assembly. The answer was : Feature flag!

What is a feature flag? It's a concept that will allow to enable/disable some features or portion of code depending on a configuration.

Let's take an example where a plugin must execute two features : Feature A and Feature B
public class MyPlugin : IPlugin
{
public void Execute(IServiceProvider serviceProvider)
{
var service = new MyCustomService();
service.ExecuteFeatureA();
service.ExecuteFeatureB();
}
}
We need to find a way to execute conditionally these methods, let's say because feature B is not tested or completed yet but we need to ship the assembly for the feature A.

What I generally use is the unsecure configuration of plugin steps to store a JSON that will explain what feature needs to be activated or not. Here is what the JSON looks like:
{"Features":[{"Enabled":true,"Name":"FeatureA"},{"Enabled":false,"Name":"FeatureB"}]}

So, in the constructor, I'm deserializing the configuration of the plugin step, so that I can use it easily in the Execute method. 

public class MyPlugin : IPlugin
{
private readonly PluginFeature _feature;

public MyPlugin(string unsecureConfiguration, string secureConfiguration)
{
if (!string.IsNullOrEmpty(unsecureConfiguration))
{
_feature =
SerializerHelper.ReadObject<PluginFeature>(
new MemoryStream(Encoding.Default.GetBytes(unsecureConfiguration)));
}
}

public void Execute(IServiceProvider serviceProvider)
{
var service = new MyCustomService();

if (_feature.Features.FirstOrDefault(f => f.Name == "FeatureA")?.Enabled ?? true)
{
service.ExecuteFeatureA();
}
if (_feature.Features.FirstOrDefault(f => f.Name == "FeatureB")?.Enabled ?? true)
{
service.ExecuteFeatureB();
}
}
}
The benefit of this implementation is it does not require any query to find the flag. Because, yes, we could also use a custom entity or environment variables to store the same kind of configuration but that requires to query these data.

Of course, in a real world scenario, I'm using a base class that handles all this code automatically, so I just have to write the following:

public class MyPlugin : Plugin
{
public MyPlugin(string unsecureConfiguration, string secureConfiguration) : base(unsecureConfiguration, secureConfiguration)
{
}

public override void PostOperationCreate(CreationServiceProvider serviceProvider)
{
var service = new MyCustomService(serviceProvider);

if (IsFeatureEnabled("FeatureA"))
{
service.ExecuteFeatureA();
}
if (IsFeatureEnabled("FeatureB"))
{
service.ExecuteFeatureB();
}
}
}


This was originally posted here.

Comments

*This post is locked for comments