Toggle features when delivering your product to multiple clients in .NET Core There are several ways of doing a feature toggle, choosing the right way depends on what you need to achieve. Annika Hey Design Principal Atanas Atanasov Software Development Manager – Agile Frameworks Björn Stansvik Founder & Chief Executive Officer Daniela Nazim MentorMate Alumni Dimitar Dobrev MentorMate Alumni Craig Knighton Chief Operating Officer Eleonora Georgieva Global VP, Delivery George Dormishev System Administration Manager Ivaylo Kostadinov Director, Software Engineering - .NET Jamie Bolseth MentorMate Alumni Jay Miller President Jeni Kyuchukova Director, Quality Engineering Jessica Anderson VP of Finance and Administration Liz Spolyar Global Director, Continuation Engineering Nick Curran Technical Architect Nikolay Lyubchev Global Director, Talent Acquisition, MentorMate Stefan Tsvyatkov Director, Software Engineering - Mobile Stefan Tzanev Chief Financial Officer Vesselin Dobrev General Manager (Bulgaria) Sylvia Vassileva Software Development Manager - Spok Filip Gajtanovski Software Development Manager - Storyworks Krasimir K. Nikolov VP of Technology Katherine Kelly Director of Operations (USA) Carrie Siewert Strategic Account Manager Brady Swanson Global Director, Marketing Eve Poeschl MentorMate Alumni Ryan Peña MentorMate Alumni Vassil Vassilev Software Development Manager - .NET Pavel Petrov Director, Software Engineering - LAMP&FE Ivan Peev Senior Technology Manager Bob Reuss MentorMate Alumni Vera Kasapova QA Manager Greta Yamacheva QA Manager Robert Samuelsson General Manager (Sweden) Kyle Simmons Solutions Architect Robin Thomas Solutions Architect Nataliya Naydenova MentorMate Alumni Adam Malone Alexander Dimitrov Enterprise Architect Andrea Kates CEO, LaunchPad Central Andrew Eklund CEO, Ciceron Andrew Marinov Angel Nikolov MentorMate Alumni Anurag Shukla Aron Wolde MentorMate Alumni Ashley Goodridge Office Assistant Benjamin Gramlich MentorMate Alumni Chris Black MentorMate Alumni Christa Haeg MentorMate Alumni Colin Lee MentorMate Alumni Deyan Stoynov MentorMate Alumni Dimitar Danailov MentorMate Alumni Dobrinka Tabakova Doug Leatherman Emily Genco MentorMate Alumni Fanka Vassileva Gabriela Zagarova MentorMate Alumni Gary Conkright CEO, physIQ Gary Fingerhut Executive Director, Cleveland Clinic Innovations Gavin Finden MentorMate Alumni Georgi Graham Klang Hyusein Hyuseinov Senior Automation QA Ian Good Global VP, Operations Iva Jack Cosentino James Williams John Byrne Kaloyan Stoilkov MentorMate Alumni Kosta Hristov Krasimir Gatev Senior Android Developer Lazar Petrakiev Lyubomir Dobrev Senior .NET Developer Lubomir Velkov Marin Yotovski Mark Smith MentorMate Alumni Martin Dimitrov MentorMate Alumni Martin Kalyonski Mike Hagan MentorMate Alumni Nikolay Andonov Nikolay Arhangelov Riley Panko Guest Contributor Roger Ferguson MentorMate Alumni Ryan Sysko Chairman, WellDoc Ryan Blake MentorMate Alumnus Sarah Rockholt MentorMate Alumni Sean McDevitt CEO, Sensei Siyana Slavova Stanislas Walden MentorMate Alumni Stanislav Atanasov Stanislava Bogdanova MentorMate Alumni Stefanie Trimble MentorMate Alumnus Stephen Fluin Stoyan Stoyanov MentorMate Alumnus Tessa Cacek Staffing Manager Tom Clemens MentorMate Alumnus V8 JavaScript Engine Viktor Mitev Yolanda Petkova Marketing Design Lead Pete Anderson Lead Product Owner, Target Vasil Nonchev Java Software Development Manager Dilyana Totseva QA Manager Stanimir Nikolov Software Development Lead - iOS, MentorMate Rosen Kolev Technology Principal Dimitar Mihaylov MentorMate Alumni Nikola Genov Software Architect - .NET Neli Todorova Software Development Manager - LAMP Yavor Dimitrov MentorMate Alumni Georgi Karanedyalkov Software Development Lead - Android, MentorMate Denislav Ganchev Technology Principal Stefan Shopov QA Manager Konstantin Rusev Java Developer Borislav Dimitrov Senior Android Developer, MentorMate Tsvetelina Lazarova MentorMate Alumni Dimitar Gadzhev Developer Plamen Stoev Software Development Manager - Front-end Jake Nelsen Senior Experience Designer Zlati Pehlivanov Senior Software Engineer II Kate Tolmie Senior Experience Designer Martin Angelov Director, Software Engineering - LAMP&FE, MentorMate Dimitar Zhelev Senior .NET Developer Joel Swenson Content Manager Kiril Ivanov Quality Assurance Analyst Viktor Hristoskov Software Development Lead - iOS, MentorMate Violeta Nikolcheva Database Developer Biliana Kadakevlieva Senior Quality Assurance Analyst Chris McLeod Senior Solutions Consultant Antonii Georgiev Junior .NET Developer Alexander Rusev Front-End Developer Matt Erickson MentorMate Alumni Brian Buchkosky Global Director, PMO David Tran MentorMate Alumni Kristin Krueger MentorMate Alumni Magdalena Chervenkova Business Analyst Denny Royal Chief Design Officer Joe Bodell MentorMate Alumni Viktoria Chuchumisheva HR Manager Kalina Tekelieva Senior Content Marketing Artist Daniel Rankov MentorMate Alumni Alexander Alexandrov BA Lead MentorMate Clint Rowles VP, Business Development Nikola Donev SysOps & DevOps Lead Tseko Tsolov Frontend Developer Denislav Lefterov Automation QA Analyst Dilyana Kodjamanova MentorMate Alumni Emma Jorstad Project Manager, Lead Georgi Georgiev Software Development Lead - LAMP, MentorMate Martin Panayotov Senior iOS Developer, MentorMate John Blake Senior Account Manager Tyler Compton Solutions Architect Nikola Peevski Software Developer — Lamp & Front-End Aaron Whitney Director of Client Strategy Veliko Ivanov Senior Cloud Engineer Suzanne O’Brien Senior Project Manager Svetlin Stanchev Software Development Lead - Front-end, MentorMate Todor Todorov Senior Cloud Engineer Kate Stamatova Senior QA Analyst Frank Anselmo Global Director, Project Management Gyuner Zeki Solutions Architect Galin Stanchev QA Analyst Sarah Hoops Business Development Manager Brenden Diehl Business Development Manager Anna Krivova Software Development Lead - Front-end, MentorMate Ivelina Kavalova Senior Business Analyst, MentorMate Paul Sanders MentorMate Alumni Jim Cikanek Senior Client Strategist Samuil Yanovski Software Development Manager - Android, MentorMate Krasimir Gatev Senior Android Developer, MentorMate Kristina Goryalova Talent Acquisition Manager Elena Petrova HR Specialist Jay Matre Senior Business Architect, MentorMate Lilyana Dimitrova QA Specialist Josh Marquart Chief Strategy Officer Mario Gorki Senior Mobile Developer Simeon Zhekov Cloud Engineer Hristo Stoyanov Cloud & DevOps Lead Ben Wallace Enterprise Architect Boyan Stoyanov Data & Dota Specialist Petya Ivanova Director, Software Engineering - Java Sebastian Ortiz-Chamorro VP of Engineering, Latin America Consuelo Merino Director of Operations Large software products with many complex features often need to be tailored to the different needs of various clients. Getting this right is important, as clients will not want to pay for features that they are not using. Paying for an expensive service only to use 20% of its functionalities is never ideal. For example, a factory management system that includes access control management, employee management, goods and transportation management, among other things, is designed for manufacturing companies. Ideally, the leaders of a manufacturing company buy only the features they need and plan on using, such as access control and employee management. Perhaps over time, those leaders will decide they need to buy additional functionalities through a service provider. But the idea of flexible delivery of functions does not pertain only to large and complex applications. You may want to deliver one small feature to some of your clients, but not others. Another option is to deliver experimental or bonus features for clients that have agreed to as much. For all these cases, it’s necessary to implement some kind of feature toggle. There are several ways of doing a feature toggle, choosing the right way depends on what you need to achieve. There are pros and cons to consider for each approach. Approach #1: Using Dynamic Feature Toggle With this approach, developers produce and ship all of the application’s, but disable and enable specific features based on clients’ predetermined configurations. What are the Pros and Cons of Approach #1? Pros Developers can easily enable and disable different features for clients based on their needs without the need of another installation. Cons When all of the application’s code is delivered to the client, there may be a lot of unused, and therefore unnecessary, code. If teams maintain poor control over client configuration, the client can enable features they are not supposed to access. How Do You Implement Dynamic Feature Toggle? For this approach, use a toggle features framework. Here are some of the existing frameworks that do just that: NFeature FlipIt FeatureToggle FeatureSwitcher FeatureBee Some of this frameworks work only for .NET Framework. The FeatureToggle by Jason Roberts has a version for .NET standards as well. We can also write our own Toggle functionality because the code for that is not big. See this example: enum Feature { Feature1, Feature2 } static class FeatureToggle { public static IEnumerable Features { get; set; } public static bool IsEnabled(Feature feature) => Features.Contains(feature); } public class Startup { public Startup(IConfiguration configuration) => FeatureToggle.Features = configuration.GetValue<string[]>("ActiveFeatures") .Select(it => Enum.Parse(it)); } FeatureToggle.IsEnabled(Feature.Feature1); Approach #2: Deliver Only the Necessary Features Another option is to deliver to your clients only the features that have been activated, and nothing else. This can be achieved by managing the build process to include or exclude certain modules when building the application. For example, if a team wants to build the application with only Feature1 and Feature2 included, they can use “& build.ps1 -Feature1 -Feature2” to create the application that includes only those features. What are the Pros and Cons of Approach #2? Pros We deliver a smaller package to the client. It is more secure because the client cannot activate any features we don’t want him to use. Cons It is not flexible because we cannot activate/deactivate features for him. The client needs to reinstall the product to receive new features or we need to provide external auto-update functionality. How Do You Implement Only the Necessary Features? First, we need to make sure that every feature is in a different assembly so they can be delivered separately. Here I have uploaded a project that is an example of this approach. The project represents a calculator that does binary operations. The calculator has two features: BasicCalculator – include addition and subtraction ExtendedCalculator – include division and multiplication. Here every feature is in a class library so it can be built separately. After we build a feature class library we copy the output files in a staging location. FeatureToggle.BasicCalculator.csproj and FeatureToggle.ExtendedCalculator.csproj <Target Name="AfterBuildCopyFilesToExtLocation" AfterTargets="Build"> <ItemGroup> <_CopyBuildItems Include="$(OutputPath)*.*" /> </ItemGroup> <Copy SourceFiles="@(_CopyBuildItems)" DestinationFolder="..FeatureToggle.Webobj$(Configuration)ext" /> </Target> And when we build the main application we include the built features that are in the obj/$(Configuration)/ext folder. Note: ResolvedFileToPublish is a msbuild variable that is used when publishing. See target “ComputeFilesToPublish” in Microsoft.NET.Publish.targets in your current dotnet sdk folder. FeatureToggle.Web.csproj <Target Name="CopyFeatureAssembliesFiles" AfterTargets="CopyFilesToOutputDirectory"> <ItemGroup> <FeatureAssemlies Include="obj/$(Configuration)/ext/*.*" /> <ResolvedFileToPublish Include="@(FeatureAssemlies)"> <RelativePath>%(Filename)%(Extension)</RelativePath> </ResolvedFileToPublish> </ItemGroup> <Copy SourceFiles="@(FeatureAssemlies)" DestinationFiles="@(FeatureAssemlies->'$(OutDir)%(Filename)%(Extension)')" Condition="'$(CopyBuildOutputToOutputDirectory)' == 'true' and '$(SkipCopyBuildProduct)' != 'true'"> <Output TaskParameter="DestinationFiles" ItemName="FileWrites"/> </Copy> </Target> How are features excluded from the application? We are not going to create references to the feature class libraries. We use what is called assembly scanning in LightInject. This feature is included in other DI & IoC frameworks. The idea is that the framework searches for a given assembly and tries to load and register services dynamically from these assemblies. The basic approach would be to just call: container.RegisterAssembly("FeatureToggle.*Calculator.dll") Note: In the example application I have registered my own IAssemblyLoader, because the current default one has some troubles in .NET Core 2.0. Now if we want to only have BasicCalculator feature we do: dotnet clean dotnet build FeatureToggle.BasicCalculator dotnet publish FeatureToggle.Web -o publish Conclusion Both approaches are relevant and can be used, depending on how you deliver your applications and what you need. When you want to dynamically switch features on and off, it is better to use the first approach. When you want to be more secure, I recommend using the second approach. Include a feature toggle only when you need to. But at the start of a new software development project, consider whether a feature toggle could be useful, as it becomes more costly the change the application’s design as teams progress through the development lifecycle. Tags DevelopmentWebSupport Share Share on Facebook Share on LinkedIn Share on Twitter Share Share on Facebook Share on LinkedIn Share on Twitter Sign up for our monthly newsletter. Sign up for our monthly newsletter.