Skip to content

Commit caa2ef2

Browse files
committed
#23 add feature toggle
1 parent 43f1758 commit caa2ef2

File tree

12 files changed

+397
-337
lines changed

12 files changed

+397
-337
lines changed

samples/BiMonetaryApi/appsettings.json

Lines changed: 32 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -8,41 +8,41 @@
88
"CurrentUri": "http://localhost:54408"
99
}
1010
},
11-
"Mongo": {
12-
"Enabled": true,
13-
"ConnectionString": "mongodb://127.0.0.1:27017",
14-
"Database": "BiMonetaryApi"
15-
},
16-
"ApiVersion": {
17-
"Enabled": true
18-
},
19-
"OpenApi": {
20-
"Enabled": true,
21-
"UI": {
22-
"Enabled": true
11+
"Features": {
12+
"Mongo": {
13+
"Enabled": true,
14+
"ConnectionString": "mongodb://127.0.0.1:27017",
15+
"Database": "BiMonetaryApi"
16+
},
17+
"ApiVersion": { "Enabled": true },
18+
"OpenApi": {
19+
"Enabled": true,
20+
"UI": {
21+
"Enabled": true
22+
},
23+
"ApiInfo": {
24+
"Title": "BiMonetary API",
25+
"Description": "An application with Swagger, Swashbuckle, and API versioning.",
26+
"ContactName": "Vietnam Devs",
27+
"ContactEmail": "[email protected]",
28+
"TermOfService": "Shareware",
29+
"LicenseName": "MIT",
30+
"LicenseUrl": "https://github.com/cloudnative-netcore/netcorekit/blob/master/LICENSE"
31+
}
2332
},
24-
"ApiInfo": {
25-
"Title": "BiMonetary API",
26-
"Description": "An application with Swagger, Swashbuckle, and API versioning.",
27-
"ContactName": "Vietnam Devs",
28-
"ContactEmail": "[email protected]",
29-
"TermOfService": "Shareware",
30-
"LicenseName": "MIT",
31-
"LicenseUrl": "https://github.com/cloudnative-netcore/netcorekit/blob/master/LICENSE"
33+
"AuthN": {
34+
"Enabled": true,
35+
"ClaimToScopeMap": {
36+
"access_example1_api": "example1_api_scope",
37+
"access_example2_api": "example2_api_scope"
38+
},
39+
"Scopes": {
40+
"example1_api_scope": "Example 1 APIs",
41+
"example2_api_scope": "Example 2 APIs"
42+
},
43+
"Audience": "api"
3244
}
3345
},
34-
"AuthN": {
35-
"Enabled": true,
36-
"ClaimToScopeMap": {
37-
"access_example1_api": "example1_api_scope",
38-
"access_example2_api": "example2_api_scope"
39-
},
40-
"Scopes": {
41-
"example1_api_scope": "Example 1 APIs",
42-
"example2_api_scope": "Example 2 APIs"
43-
},
44-
"Audience": "api"
45-
},
4646
"Logging": {
4747
"LogLevel": {
4848
"Default": "Warning"

src/NetCoreKit.Infrastructure.AspNetCore.Miniservice/AppBuilderExtensions.cs

Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
using NetCoreKit.Infrastructure.AspNetCore.Configuration;
1414
using NetCoreKit.Infrastructure.AspNetCore.Extensions;
1515
using NetCoreKit.Infrastructure.AspNetCore.Middlewares;
16+
using NetCoreKit.Infrastructure.Features;
1617
using StackExchange.Profiling;
1718
using static NetCoreKit.Utils.Helpers.IdHelper;
1819

@@ -25,6 +26,7 @@ public static IApplicationBuilder UseMiniService(this IApplicationBuilder app)
2526
var config = app.ApplicationServices.GetRequiredService<IConfiguration>();
2627
var loggerFactory = app.ApplicationServices.GetRequiredService<ILoggerFactory>();
2728
var env = app.ApplicationServices.GetRequiredService<IHostingEnvironment>();
29+
var feature = app.ApplicationServices.GetRequiredService<IFeature>();
2830

2931
// #1
3032
loggerFactory.AddConsole(config.GetSection("Logging"));
@@ -40,10 +42,8 @@ public static IApplicationBuilder UseMiniService(this IApplicationBuilder app)
4042
app.UseDeveloperExceptionPage();
4143
app.UseDatabaseErrorPage();
4244

43-
if (config.GetValue("OpenApi:Profiler:Enabled", false))
44-
{
45+
if (feature.IsEnabled("OpenApi:Profiler"))
4546
app.UseMiniProfiler();
46-
}
4747
}
4848
else
4949
{
@@ -93,10 +93,8 @@ public static IApplicationBuilder UseMiniService(this IApplicationBuilder app)
9393

9494
app.UseMiddleware<ErrorHandlerMiddleware>();
9595

96-
if (config.GetValue("OpenApi:Profiler:Enabled", false))
97-
{
96+
if (feature.IsEnabled("OpenApi:Profiler"))
9897
app.UseMiddleware<MiniProfilerMiddleware>();
99-
}
10098

10199
// #3
102100
#pragma warning disable CS1998 // Async method lacks 'await' operators and will run synchronously
@@ -121,7 +119,7 @@ public static IApplicationBuilder UseMiniService(this IApplicationBuilder app)
121119
app.UseCors("CorsPolicy");
122120

123121
// #7
124-
if (config.GetValue("AuthN:Enabled", false))
122+
if (feature.IsEnabled("AuthN"))
125123
app.UseAuthentication();
126124

127125
// #8
@@ -131,10 +129,10 @@ public static IApplicationBuilder UseMiniService(this IApplicationBuilder app)
131129
basePath = config.GetBasePath();
132130
var currentHostUri = config.GetExternalCurrentHostUri();
133131

134-
if (config.GetValue("OpenApi:Enabled", false))
132+
if (feature.IsEnabled("OpenApi"))
135133
app.UseSwagger();
136134

137-
if (config.GetValue("OpenApi:UI:Enabled", false))
135+
if (feature.IsEnabled("OpenApi:UI"))
138136
app.UseSwaggerUI(
139137
c =>
140138
{
@@ -146,15 +144,15 @@ public static IApplicationBuilder UseMiniService(this IApplicationBuilder app)
146144
$"{basePath}swagger/{description.GroupName}/swagger.json",
147145
description.GroupName.ToUpperInvariant());
148146

149-
if (config.GetValue("AuthN:Enabled", false))
147+
if (feature.IsEnabled("AuthN"))
150148
{
151149
c.OAuthClientId("swagger_id");
152150
c.OAuthClientSecret("secret".Sha256());
153151
c.OAuthAppName("swagger_app");
154152
c.OAuth2RedirectUrl($"{currentHostUri}/swagger/oauth2-redirect.html");
155153
}
156154

157-
if (config.GetValue("OpenApi:Profiler:Enabled", false))
155+
if (feature.IsEnabled("OpenApi:Profiler"))
158156
{
159157
c.IndexStream = () =>
160158
typeof(ServiceCollectionExtensions)

src/NetCoreKit.Infrastructure.AspNetCore.Miniservice/ConfigurationExtensions.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ public static string GetAudience(this IConfiguration config)
2424
private static AuthNOptions GetAuthNOptions(IConfiguration config)
2525
{
2626
var options = new AuthNOptions();
27-
config.GetSection("AuthN").Bind(options);
27+
config.GetSection("Features:AuthN").Bind(options);
2828
return options;
2929
}
3030
}
Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
using System;
2+
using System.Linq;
3+
using Microsoft.AspNetCore.Hosting;
4+
using Microsoft.EntityFrameworkCore;
5+
using Microsoft.Extensions.Configuration;
6+
using Microsoft.Extensions.DependencyInjection;
7+
using NetCoreKit.Domain;
8+
using NetCoreKit.Infrastructure.AspNetCore.CleanArch;
9+
using NetCoreKit.Infrastructure.EfCore;
10+
using NetCoreKit.Infrastructure.EfCore.Db;
11+
using NetCoreKit.Infrastructure.Features;
12+
13+
namespace NetCoreKit.Infrastructure.AspNetCore.Miniservice
14+
{
15+
public static partial class ServiceCollectionExtensions
16+
{
17+
public static IServiceCollection AddEfCoreMiniService<TDbContext>(
18+
this IServiceCollection services,
19+
Action<IServiceCollection> preScopeAction = null,
20+
Action<IServiceCollection, IServiceProvider> afterDbScopeAction = null)
21+
where TDbContext : DbContext
22+
{
23+
services.AddFeatureToggle();
24+
25+
using (var scope = services.BuildServiceProvider().GetService<IServiceScopeFactory>().CreateScope())
26+
{
27+
var svcProvider = scope.ServiceProvider;
28+
var config = svcProvider.GetRequiredService<IConfiguration>();
29+
var env = svcProvider.GetRequiredService<IHostingEnvironment>();
30+
var feature = svcProvider.GetRequiredService<IFeature>();
31+
32+
// let registering the database providers or others from the outside
33+
preScopeAction?.Invoke(services);
34+
// services.AddScoped<DbHealthCheckAndMigration>();
35+
36+
// #1
37+
if (feature.IsEnabled("EfCore"))
38+
{
39+
if (feature.IsEnabled("Mongo")) throw new Exception("Please turn off MongoDb settings.");
40+
41+
services.AddDbContextPool<TDbContext>((sp, o) =>
42+
{
43+
var extendOptionsBuilder = sp.GetRequiredService<IExtendDbContextOptionsBuilder>();
44+
var connStringFactory = sp.GetRequiredService<IDatabaseConnectionStringFactory>();
45+
extendOptionsBuilder.Extend(o, connStringFactory,
46+
config.LoadApplicationAssemblies().FirstOrDefault()?.GetName().Name);
47+
});
48+
49+
services.AddScoped<DbContext>(resolver => resolver.GetService<TDbContext>());
50+
services.AddGenericRepository();
51+
}
52+
53+
// let outside inject more logic (like more healthcheck endpoints...)
54+
afterDbScopeAction?.Invoke(services, svcProvider);
55+
56+
// RestClient out of the box
57+
services.AddRestClientCore();
58+
59+
// DomainEventBus for handling the published event from the domain object
60+
services.AddSingleton<IDomainEventBus, MemoryDomainEventBus>();
61+
62+
// #3
63+
if (feature.IsEnabled("CleanArch"))
64+
services.AddCleanArch(config.LoadFullAssemblies());
65+
66+
services.AddCacheCore();
67+
68+
// #4
69+
if (feature.IsEnabled("ApiVersion"))
70+
services.AddApiVersionCore(config);
71+
72+
// #5
73+
services.AddMvcCore(config);
74+
75+
// #6
76+
services.AddDetailExceptionCore();
77+
78+
// #7
79+
if (feature.IsEnabled("AuthN"))
80+
services.AddAuthNCore(config, env);
81+
82+
// #8
83+
if (feature.IsEnabled("OpenApi"))
84+
services.AddOpenApiCore(config, feature);
85+
86+
// #9
87+
services.AddCorsCore();
88+
89+
// #10
90+
services.AddHeaderForwardCore(env);
91+
92+
if (feature.IsEnabled("OpenApi:Profiler"))
93+
services.AddApiProfilerCore();
94+
}
95+
96+
return services;
97+
}
98+
}
99+
}

0 commit comments

Comments
 (0)