Last active
August 30, 2020 16:28
-
-
Save LucGosso/d74429368c85d1e937a87968726d35ce to your computer and use it in GitHub Desktop.
Simple Feature Flag Service - blob post https://devblog.gosso.se/?p=1410
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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