Esquio -Feature Toggles for .NET Applications

July 31, 2023 by Khalid Abuhakmeh

Software development teams need help maintaining users' existing features and delivering new solutions. There are multiple strategies to address this problem, but a popular approach used by many high-functioning teams has been feature toggles. Feature toggles can be an alternative to feature branches, allowing teams to do more informed A/B testing on non-production-ready features to increase the user feedback loop and improve the software.

From a high level, when implementing feature toggles, all newer software features are gated behind an enabled/disabled flag, also known as a toggle. While the result may seem simple, toggles can also have more complex logic enabling them for users or specific scenarios. Feature toggles can help teams deliver newer features to a production environment without the jarring changes typically associated with releases.

Feature toggles can offer developers a longer period to test and validate new features while maintaining older implementations side-by-side. Yes, it takes a bit more planning on the part of the developers, but ultimately its benefits outweigh its drawbacks. They can also provide product managers and stakeholders more control in the development and deployment process, giving teams more time to develop newer features and maintain a codebase.

For folks interested in implementing feature toggles into their applications, the .NET Foundation project Esquio offers a great set of features that integrate with .NET and ASP.NET Core with its many programming paradigms.

In this post, we'll see how to set up an ASP.NET Core application with Esquio and toggle a new messaging feature. We'll also consider an essential aspect of feature toggles, maintenance.

Getting Started

Esquio works with all ASP.NET Core paradigms, including ASP.NET Core MVC, Razor Pages, and Minimal APIs. Regardless of what you're building, Esquio provides access to its toggling capabilities through endpoint metadata, action filters, and Razor tag helpers. It's a complete solution. This post will start with an ASP.NET Core Web App template and focus on Razor Pages.

Once you've created the web application project, you must add the Esquio packages.

dotnet add package Esquio.AspNetCore
dotnet add package Esquio.Configuration.Store

You may have noticed the Esquio.Configuration.Store package. Esquio needs a location to read toggle information, and the most convenient location for most folks is the configuration file. Esquio also provides store mechanisms for HTTP endpoints and Entity Framework Core for distributed production scenarios.

Next, update your service collection registration to add the Esquio services and the configuration store.

var builder = WebApplication.CreateBuilder(args);  

// Add services to the container.  
builder.Services.AddRazorPages();  
builder.Services  
    .AddEsquio()  
    .AddAspNetCoreDefaultServices()  
    .AddConfigurationStore(builder.Configuration);

Next, you'll need to add an Esquio section to your configuration. You can operate each feature based on the Enabled value or create C# based Toggles. Esquio ships with two built-in toggles of EnvironmentToggle and FromToToggle (date ranges), and you can implement your own. We'll stick to the boolean flag for this post.

{  
  "Logging": {  
    "LogLevel": {  
      "Default": "Information",  
      "Microsoft.AspNetCore": "Warning"  
    }  
  },  
  "AllowedHosts": "*",  
  "Esquio": {  
    "Products": [  
      {  
        "Name": "default",  
        "Features": [  
          {  
            "Name": "HiddenGem",  
            "Enabled": true,  
            "Toggles": []  
          }  
        ]  
      }  
    ]  
  }  
}

If you use any feature toggles on Minimal API or MVC Core endpoints, you'll also want to add the EsquioMiddleware in your request pipeline registration. Depending on future toggles, you want to add the registration in the pipeline after the UseAuthorization call so you can access the current User property on the incoming request, otherwise registering the middleware anywhere after UseRouting should be adequate.

var app = builder.Build();  

// Configure the HTTP request pipeline.  
if (!app.Environment.IsDevelopment())  
{  
    app.UseExceptionHandler("/Error");  
    // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.  
    app.UseHsts();  
}  

app.UseHttpsRedirection();  
app.UseStaticFiles();  
app.UseRouting();  
app.UseAuthorization();  
// add Esquio Middleware here  
app.MapEsquio();  
app.MapRazorPages();  

app.Run();

Next, add the Esquio tag helper registrations to the _ViewImports.cshtml file in the web application.

@using WebApplication10
@using Esquio
@using Esquio.Abstractions
@using Esquio.AspNetCore  

@namespace WebApplication10.Pages  

@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers  
@addTagHelper *, Esquio.AspNetCore

Let's recap where we are so far in the setup process:

  1. We've added Esquio to our ASP.NET Core application and the required services.
  2. We're using a Configuration store located in appSettings.json.
  3. We've registered Esquio services in the services collection.
  4. We've added EsquioMiddleware to support server-side features for endpoints.
  5. We've registered the tag helpers for Razor views.

Now, let's get to some feature toggling.

Toggling Features

As you may have noticed in the appSettings.json file, we have a feature named HiddenGem. We'll use this to show users a message in our Index.cshtml Razor page. Add the following Razor to your Index.cshtml file.

@page  
@model IndexModel  
@{  
    ViewData["Title"] = "Home page";  
}  

<div class="text-center">  
    <h1 class="display-4">Welcome</h1>  
    <p>Learn about <a href="https://learn.microsoft.com/aspnet/core">  
        building Web apps with ASP.NET Core  
    </a>.</p>  

    <feature names="HiddenGem">  
        <h2>.NET ❤️ Esquio</h2>  
        <p>Check out <a href="https://esquio.readthedocs.io">the Esquio docs</a></p>  
    </feature>  

</div>

The feature element is an ASP.NET Core tag helper which uses the configuration store to determine if the feature is enabled. If all goes well, you should see the ".NET ❤️ Esquio" message on the page. You can also toggle these settings without restarting your app by changing the flag value in appSettings.json.

Awesome, right?! You can add as many feature toggles as you like from here, but what happens when there are too many? Well, let's discuss that in the next section.

Let's Talk About Maintenance

If you're new to feature toggles, you may be worried about the noise-to-signal ratio in your code base. You may wonder, "How can all my application's feature toggles coexist without becoming a maintenance nightmare?" As a recommendation, here is a typical lifecycle of a toggle when implementing Esquio in your apps:

  1. Locate an area of improvement.
  2. Determine how to implement that feature with the least disruption.
  3. Implement the feature toggle.
  4. Deploy the feature for testing/toggling.
  5. Determine when you've been successful.
  6. Once reached, subsequent deployments remove the toggle and Esquio code.
  7. Repeat :)

While you can certainly keep all the toggles you've ever added to your application, removing individual toggles is the best practice as your application evolves. Culling toggles helps you reduce branching logic in your applications, reducing the possibility of interaction bugs; fewer branches means less opportunity for edge cases. It also helps everyone understand what features are still in an experimental phase and which are now part of the core product.

Setting deadlines and due dates for features can help your team determine when work should happen to remove toggles and when work for new toggles should begin. Your timeline will depend on your features, so discuss the strategy with stakeholders and colleagues. Like all code, you want to pay down technical debt before it becomes overwhelming to the resources available to your organization. Remember, feature toggles aim to accelerate the development feedback loop and shorten the time to market. You will need to understand and execute a sound strategy to see any advantages to this approach.

Conclusion

Esquio is an excellent feature toggle library that has thought about the breadth of options under the ASP.NET Core umbrella. Whether using Minimal APIs, Razor Pages, MVC Core, or a SPA framework, you'll find options to support toggling features. As seen in the documentation, Esquio can also be used in any .NET application. It's a fantastic library with an opportunity to support whatever you can imagine building. With a clear feature toggle strategy, teams can accelerate delivering solutions to users while maintaining high-quality software. It's a winning combination.

Thank you to the maintainers of Esquio for supporting the library, making it available to others, and being a .NET Foundation member project. If you'd like to get involved in helping the project reach more folks in the .NET community, please share this post. If you'd like to learn more about Esquio, visit their GitHub page and documentation.

As always, thank you to our project members and the .NET community that helps them thrive.