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);
        }
Exemplo n.º 2
0
        /// <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);
        }