GitLab feature management for .Net
Tags: dotnet, learning, gitlab, featureflag
Published: 2023-08-17 16:01:24

## Motivation
Provide a mechanism for continued delivery together with continued development.

## Solution
Use trunk-based development and feature toggles.

## Implementation
Before starting to work with a feature, we need to create a new feature flag in GitLab and disable it. After that, all development should be branched with a feature toggle. When the feature is developed and deployed we can enable a feature in GitLab for the environment and it will activate during runtime. After the next release, we delete a feature flag and clean up the code.

### GitLab feature management
GitLab provides a built-in solution for feature flags where we can create, add strategies, and manage. GitLab uses [unleash](https://www.getunleash.io/) client(we can also use direct GitLab API) to work with features. We can install _unleash_ NuGet package from [here](https://github.com/Unleash/unleash-client-dotnet).

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/dpvgryfw4meygpgzuu24.png)

During development, I found two weird things
1. `UnleashSettings` has a specific property for *Environment*, but the client works only when we set the GitLab environment name to **AppName**.
2. It is hard to understand where we should set **Instance ID** in `UnleashSettings`. In GitHub example - *ProjectId*, but property that work **InstanceTag**
```
var unleash = new DefaultUnleash(new UnleashSettings
{
   AppName = "environment_name" 
   UnleashApi = new Uri("API URL in GitLab config"),
   InstanceTag = "Instance ID in GitLab config",
   SendMetricsInterval = null,
});
```
### Environments
Important GitLab feature - **environments**. We deploy our solution to specific environments and we can activate/deactivate feature flags per environment. 

### Microsoft feature management
Unleash client is good enough, but we want to use 
[dotnet feature management](https://github.com/Unleash/unleash-client-dotnet), which has great integration with ASP.NET Core. To do that we should implement `IFeatureDefinitionProvider` for GitLab
```
internal class GitLabFeatureProvider : IFeatureDefinitionProvider
{
  private IUnleash unleash;
  public GitLabFeatureProvider(IUnleash unleash)
    => this.unleash = unleash;

  public async IAsyncEnumerable<FeatureDefinition> GetAllFeatureDefinitionsAsync()
  {
    await Task.CompletedTask;
    foreach (var feature in this.unleash.FeatureToggles)
    {
        yield return CreateFeatureDefinition(feature.Name, feature.Enabled);
    }
  }

  public Task<FeatureDefinition> GetFeatureDefinitionAsync(string featureName)
  {
    var active = unleash.IsEnabled(featureName);
    return Task.FromResult(CreateFeatureDefinition(featureName, active));
  }

  private static FeatureDefinition CreateFeatureDefinition(string name, bool active)
  {
    return new FeatureDefinition
    {
      Name = name,
      EnabledFor = active
        ? new[] { new FeatureFilterConfiguration { Name = "AlwaysOn" } }
        : Array.Empty<FeatureFilterConfiguration>()
    };
  }
}
```
### Using feature management
In the end, we need to register feature management
```
.AddFeatureManagement()
.AddSingleton<IFeatureDefinitionProvider, GitLabFeatureProvider>();
```
inject `IFeatureManager` into our solution and use it
`await feature.IsEnabledAsync(nameof(FeatureFlags.myfeature))`

## Conclusions
1. We manage our features during runtime using GitLab feature flags per environment
2. We can rollback feature during runtime
3. We develop and deploy without impact to the system and end users.

## Help links
* https://trunkbaseddevelopment.com
* https://docs.gitlab.com/ee/operations/feature_flags.html
* https://github.com/microsoft/FeatureManagement-Dotnet