コード例 #1
0
        public static IServiceCollection AddFeatureFlags(
            this IServiceCollection service,
            FeatureFlagOptions options = default(FeatureFlagOptions))
        {
            service.AddSingleton(new FeatureFlags(options.Provider)); // TODO: Remove in v2?

            foreach (var featureType in options.FeatureFlagAssemblies.GetFeatureTypes())
            {
                var feature = (Feature)Activator.CreateInstance(featureType);

                service.Add(new ServiceDescriptor(featureType, provider =>
                {
                    var featureFlags = provider.GetRequiredService <FeatureFlags>();

                    var featureFlag = featureFlags.Get(featureType)
                                      .ConfigureAwait(false)
                                      .GetAwaiter()
                                      .GetResult();

                    return(featureFlag);
                }, feature.ServiceLifetime));
            }

            return(service);
        }
コード例 #2
0
        /// <summary>
        /// This should only be used for testing as values
        /// are not persisted to any long term storage.
        /// </summary>
        public static FeatureFlagOptions UseInMemoryFeatureProvider(
            this FeatureFlagOptions options)
        {
            options.Provider = new InMemoryFeatureProvider(
                options.FeatureFlagAssemblies);

            return(options);
        }
コード例 #3
0
        public static IServiceCollection AddFeatureFlags(
            this IServiceCollection service,
            FeatureFlagOptions options = default(FeatureFlagOptions))
        {
            service.AddSingleton(new FeatureFlags(options.Provider));

            return(service);
        }
コード例 #4
0
        public static IApplicationBuilder UseFeatureFlags(
            this IApplicationBuilder builder,
            FeatureFlagOptions options = default(FeatureFlagOptions))
        {
            builder.Map(options.UiPath, x =>
            {
                // Display UI
            });

            return(builder);
        }
コード例 #5
0
        public static FeatureFlagOptions UseCustomProvider(
            this FeatureFlagOptions options,
            IFeatureProvider provider)
        {
            if (provider == null)
            {
                throw new ArgumentNullException(nameof(provider));
            }

            options.Provider = provider;

            return(options);
        }
コード例 #6
0
        public static FeatureFlagOptions UseCachedSqlFeatureProvider(
            this FeatureFlagOptions options,
            string connectionString)
        {
            if (connectionString == null)
            {
                throw new ArgumentNullException(nameof(connectionString));
            }

            options.Provider = new CachedSqlFeatureProvider(
                options.FeatureFlagAssemblies,
                connectionString);

            return(options);
        }
コード例 #7
0
        public static IApplicationBuilder UseFeatureFlags(
            this IApplicationBuilder builder,
            FeatureFlagOptions options = default(FeatureFlagOptions))
        {
            if (!providerInitialized)
            {
                options.Provider.Initialize()
                .ConfigureAwait(false)
                .GetAwaiter()
                .GetResult();

                providerInitialized = true;
            }

            return(builder);
        }
コード例 #8
0
        public static IApplicationBuilder UseFeatureFlags(
            this IApplicationBuilder builder,
            FeatureFlagOptions options = default(FeatureFlagOptions))
        {
            builder.Use(async(context, next) =>
            {
                if (!providerInitialized)
                {
                    await options.Provider.Initialize().ConfigureAwait(false);
                    providerInitialized = true;
                }

                await next();
            });

            return(builder);
        }
コード例 #9
0
        public static IServiceCollection AddFeatureFlags(
            this IServiceCollection service,
            FeatureFlagOptions options = default(FeatureFlagOptions))
        {
            service.AddSingleton(new FeatureFlags(options.Provider));

            foreach (var featureType in options.FeatureFlagAssemblies.GetFeatureTypes())
            {
                service.AddTransient(featureType, provider =>
                {
                    var featureFlags = provider.GetRequiredService <FeatureFlags>();

                    var featureFlag = featureFlags.Get(featureType)
                                      .ConfigureAwait(false)
                                      .GetAwaiter()
                                      .GetResult();

                    return(featureFlag);
                });
            }

            return(service);
        }
コード例 #10
0
        public static IApplicationBuilder UseFeatureFlagsUI(
            this IApplicationBuilder builder,
            FeatureFlagOptions options = default(FeatureFlagOptions))
        {
            builder.Map(options.ApiGetPath, appBuilder =>
            {
                appBuilder.Run(async context =>
                {
                    if (context.Request.Method != HttpMethods.Get)
                    {
                        context.Response.StatusCode = StatusCodes.Status405MethodNotAllowed;
                        return;
                    }

                    var featureFlags = context.RequestServices.GetService <FeatureFlags>();

                    if (featureFlags == null)
                    {
                        throw new InvalidOperationException(
                            $"{nameof(FeatureFlags)} must be registered via AddFeatureFlags()");
                    }

                    var featureName = context.Request.Query["feature"];
                    if (string.IsNullOrEmpty(featureName))
                    {
                        context.Response.StatusCode = StatusCodes.Status400BadRequest;
                        return;
                    }

                    var featureType = options.FeatureFlagAssemblies.GetFeatureType(featureName);

                    if (featureType == null)
                    {
                        context.Response.StatusCode = StatusCodes.Status404NotFound;
                        return;
                    }

                    var feature = await featureFlags.Get(featureType).ConfigureAwait(false);

                    var json = JsonConvert.SerializeObject(feature);

                    await context.Response.WriteAsync(json).ConfigureAwait(false);
                });
            });

            builder.Map(options.ApiGetAllPath, appBuilder =>
            {
                appBuilder.Run(async context =>
                {
                    if (context.Request.Method != HttpMethods.Get)
                    {
                        context.Response.StatusCode = StatusCodes.Status405MethodNotAllowed;
                        return;
                    }

                    var featureFlags = context.RequestServices.GetService <FeatureFlags>();

                    if (featureFlags == null)
                    {
                        throw new InvalidOperationException(
                            $"{nameof(FeatureFlags)} must be registered via AddFeatureFlags()");
                    }

                    var features = new List <object>();
                    foreach (var featureType in options.FeatureFlagAssemblies.GetFeatureTypes())
                    {
                        var feature = await featureFlags.Get(featureType).ConfigureAwait(false);

                        features.Add(feature);
                    }

                    var json = JsonConvert.SerializeObject(features);

                    await context.Response.WriteAsync(json).ConfigureAwait(false);
                });
            });

            builder.Map(options.ApiSetPath, appBuilder =>
            {
                appBuilder.Run(async context =>
                {
                    if (context.Request.Method != HttpMethods.Post)
                    {
                        context.Response.StatusCode = StatusCodes.Status405MethodNotAllowed;
                        return;
                    }

                    var featureFlags = context.RequestServices.GetService <FeatureFlags>();

                    if (featureFlags == null)
                    {
                        throw new InvalidOperationException(
                            $"{nameof(FeatureFlags)} must be registered via AddFeatureFlags()");
                    }

                    string requestString;
                    using (var streamReader = new StreamReader(context.Request.Body))
                    {
                        requestString = await streamReader
                                        .ReadToEndAsync()
                                        .ConfigureAwait(false);
                    }

                    var setRequest = (FeatureSetRequest)JsonConvert.DeserializeObject(
                        requestString, typeof(FeatureSetRequest));

                    var featureType = options.FeatureFlagAssemblies.GetFeatureType(setRequest.Feature);

                    if (featureType == null)
                    {
                        context.Response.StatusCode = StatusCodes.Status404NotFound;
                        return;
                    }

                    var feature = Activator.CreateInstance(featureType);

                    (feature as Feature).Value = setRequest.Value;

                    await featureFlags.Set(feature).ConfigureAwait(false);

                    context.Response.StatusCode = StatusCodes.Status204NoContent;
                });
            });

            builder.Map(options.UiPath, x =>
            {
                x.Map($"/main.js", y => y.Run(context => context.Response.WriteManifestResource(typeof(IApplicationBuilderExtensions), "application/javascript", "main.js")));
                x.Run(context => context.Response.WriteManifestResource(typeof(IApplicationBuilderExtensions), "text/html", "index.html"));
            });

            return(builder);
        }