private async Task <FeatureFlagsSessionManager> CreateSut() { var sqlSessionManagerSettings = new SQLServerSessionManagerSettings { ConnectionString = databaseFixture.ConnectionString }; var featureFlagsSettings = new FeatureFlagsSettings( featureFlagAssemblies: new[] { typeof(FeatureFlagsSessionManagerTests).Assembly } ) { ConnectionString = databaseFixture.ConnectionString, InitializationConnectionString = databaseFixture.ConnectionString, SqlSessionManagerSettings = sqlSessionManagerSettings, }; var sut = new FeatureFlagsSessionManager( featureFlagsSettings: featureFlagsSettings ); await sqlSessionManagerSettings.CreateDatabaseTableAsync( featureFlagsSettings.InitializationConnectionString ); return(sut); }
/// <summary> /// <para>Uses <see cref="IEndpointRouteBuilder"/> to map the UI/API endpoints.</para> /// <para>Note that if you layer session managers, the value retrieved for a particular feature /// may not match what is shown in this UI. This UI/API only displays/updates the values for the /// <see cref="FeatureFlagsSessionManager"/> session manager.</para> /// <para>IMPORTANT: Controlling access of the UI / API of this library is the responsibility of the user. /// Apply authentication / authorization around the `UseFeatureFlagsUI` method as needed, as this method /// simply wires up the various endpoints.</para> /// </summary> public static IEndpointConventionBuilder MapFeatureFlagsUI( this IEndpointRouteBuilder builder, FeatureFlagsSettings settings, FeatureFlagUISettings uiSettings = default(FeatureFlagUISettings) ) { if (settings is null) { throw new ArgumentNullException(nameof(settings)); } var featureFlagsUIBuilder = new FeatureFlagsUIBuilder(); return(builder.Map( uiSettings.UIPath + "/{**path}", async context => { var path = context.Request.Path; if (path == uiSettings.ApiGetPath) { await featureFlagsUIBuilder.ApiGetPath(context, settings); return; } if (path == uiSettings.ApiGetAllPath) { await featureFlagsUIBuilder.ApiGetAllPath(context, settings); return; } if (path == uiSettings.ApiSetPath) { await featureFlagsUIBuilder.ApiSetPath(context, settings); return; } if (path == $"{uiSettings.UIPath}/main.js") { await context.Response.WriteManifestResource(typeof(UIStartupExtensions), "application/javascript", "main.js"); return; } if (path == uiSettings.UIPath) { await context.Response.WriteManifestResource(typeof(UIStartupExtensions), "text/html", "index.html"); return; } })); }
internal async Task ApiSetPath( HttpContext context, FeatureFlagsSettings settings ) { if (context.Request.Method != HttpMethods.Post) { context.Response.StatusCode = StatusCodes.Status405MethodNotAllowed; return; } var featureFlagsSessionManager = context.RequestServices.GetRequiredService <FeatureFlagsSessionManager>(); string requestString; using (var streamReader = new StreamReader(context.Request.Body)) { requestString = await streamReader .ReadToEndAsync() .ConfigureAwait(false); } var setRequest = (FeatureRequest)JsonConvert.DeserializeObject( requestString, typeof(FeatureRequest) ); if (setRequest is null) { context.Response.StatusCode = StatusCodes.Status400BadRequest; return; } var featureType = settings.GetFeatureType(setRequest.Name); if (featureType is null) { context.Response.StatusCode = StatusCodes.Status404NotFound; return; } await featureFlagsSessionManager .SetNullableAsync(setRequest.Name, setRequest.Enabled) .ConfigureAwait(false); context.Response.StatusCode = StatusCodes.Status204NoContent; }
internal async Task ApiGetPath( HttpContext context, FeatureFlagsSettings settings ) { if (context.Request.Method != HttpMethods.Get) { context.Response.StatusCode = StatusCodes.Status405MethodNotAllowed; return; } var featureFlagsSessionManager = context.RequestServices.GetRequiredService <FeatureFlagsSessionManager>(); var featureName = context.Request.Query["feature"]; if (string.IsNullOrEmpty(featureName)) { context.Response.StatusCode = StatusCodes.Status400BadRequest; return; } var featureType = settings.GetFeatureType(featureName); if (featureType is null) { context.Response.StatusCode = StatusCodes.Status404NotFound; return; } var value = await featureFlagsSessionManager.GetAsync(featureName); var response = new FeatureResponse { Name = featureName, Description = featureType.GetDescription(), Enabled = value, }; var json = JsonConvert.SerializeObject(response); await context.Response.WriteAsync(json).ConfigureAwait(false); }
internal async Task ApiGetAllPath( HttpContext context, FeatureFlagsSettings settings ) { if (context.Request.Method != HttpMethods.Get) { context.Response.StatusCode = StatusCodes.Status405MethodNotAllowed; return; } var sessionManager = context.RequestServices.GetService <FeatureFlagsSessionManager>(); if (sessionManager == null) { throw new InvalidOperationException( $"{nameof(FeatureFlagsSessionManager)} must be registered via {nameof(UIStartupExtensions.UseRimDevFeatureFlagsUI)}()"); } var features = new List <object>(); foreach (var featureType in settings.FeatureFlagTypes) { var featureName = featureType.Name; var enabled = await sessionManager.GetAsync(featureName); var featureResponse = new FeatureResponse { Name = featureName, Description = featureType.GetDescription(), Enabled = enabled, }; features.Add(featureResponse); } var json = JsonConvert.SerializeObject(features); await context.Response.WriteAsync(json).ConfigureAwait(false); }