Skip to content

Instantly share code, notes, and snippets.

@LucGosso
Last active August 30, 2020 16:28
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save LucGosso/d74429368c85d1e937a87968726d35ce to your computer and use it in GitHub Desktop.
Save LucGosso/d74429368c85d1e937a87968726d35ce to your computer and use it in GitHub Desktop.
Simple Feature Flag Service - blob post https://devblog.gosso.se/?p=1410
using AlloyTemplates.Business;
using EPiServer;
using EPiServer.Core;
using EPiServer.Personalization.VisitorGroups;
using EPiServer.ServiceLocation;
using EPiServer.Web;
using System;
using System.Configuration;
using System.Reflection;
using System.Web;
namespace Gosso.Features.FeatureFlags
{
[ServiceConfiguration(typeof(IFeatureFlagService), Lifecycle = ServiceInstanceScope.Hybrid)]
public class FeatureFlagService : IFeatureFlagService
{
protected const string PreFixKey = "FeatureFlag";
protected readonly string Flag1Key = $"{PreFixKey}:Flag1";
private ISiteSettings siteSettings;
private bool _flag1 = false;//the default value is set here
private readonly IContentLoader _contentLoader;
public FeatureFlagService(IContentLoader contentLoader)
{
_contentLoader = contentLoader;
}
private void EvalRules()
{
//get the ISiteSettings each time to get the latest updated values
siteSettings = _contentLoader.Get<ISiteSettings>(SiteDefinition.Current.StartPage, LanguageSelector.AutoDetect());
//Rule one, appsettings default
_flag1 = (ConfigurationManager.AppSettings[Flag1Key] == "true");
//Rule two, from site settings
if (siteSettings.NewFeatureEnabled)
_flag1 = siteSettings.NewFeatureEnabled;
//Rule Three, cookies per browser is set by using querystring ?featureflag:flag1=true
if (HttpContext.Current != null)
{
string cookieValue = HttpContext.Current.Request.Cookies.Get(Flag1Key)?.Value;
_flag1 = (cookieValue == "true") ? true : (cookieValue == "false") ? false : _flag1;
}
//rule four, if there exists a visitor group with this name and its true, use it.
_flag1 = EPiServer.Security.PrincipalInfo.CurrentPrincipal.IsInRole("FeatureFlag:Flag1", EPiServer.Security.SecurityEntityType.VisitorGroup) == true ? true: _flag1;
}
public bool IsFlag1Enabled { get { EvalRules(); return _flag1; } set { _flag1 = value; } }
/// <summary>
/// Used to set FeatureFlag Cookie, is called from a PageViewContextFactory or IResultFilter or what ever a page layout model is created
/// </summary>
/// <param name="key"></param>
/// <param name="value"></param>
public void SetValue(string key, bool value)
{
Type t = typeof(FeatureFlagService);
string propName = "_" + key;
var field = t.GetField(propName.ToLowerInvariant(), BindingFlags.NonPublic | BindingFlags.Instance);
if (field != null)// Change the private property value if it exists, also dont set cookie if no flag exists
{
field.SetValue(this, value);
if (HttpContext.Current != null) // set session persistant cookie
{
var c = new HttpCookie($"{PreFixKey}:{key}".ToLowerInvariant(), value.ToString().ToLower()) { /*Expires = DateTime.UtcNow.AddDays(7)*/ };
HttpContext.Current.Response.Cookies.Set(c);
}
}
}
}
public interface IFeatureFlagService
{
bool IsFlag1Enabled { get; set; }
void SetValue(string key, bool value);
}
}
//call this from Creation of LayoutModel or IResultFilter
SaveFeatureFlags(requestContext.HttpContext.Request.QueryString);
/// <summary>
/// checks if querystring key if feature flag
/// </summary>
/// <param name="q"></param>
private void SaveFeatureFlags(NameValueCollection q)
{
if (q.AllKeys.Any(x => x != null && x.ToLowerInvariant().StartsWith("featureflag:")))
{
q.AllKeys
.Where(x => x != null && x.ToLowerInvariant().StartsWith("featureflag:"))
.Select(x => SaveFeatureValue(new { key = x.ToLowerInvariant().Replace("featureflag:", ""), value = q[x] }))
.ToList();
}
}
private string SaveFeatureValue(dynamic value)
{
_featureFlagService.SetValue(value.key, value.value == "true");
return value.key;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment