Skip to content

Commit 6fff127

Browse files
committed
#28 organize the project structure a bit, also remove miniservice on nuget publish.
1 parent a761f09 commit 6fff127

File tree

15 files changed

+159
-219
lines changed

15 files changed

+159
-219
lines changed

README.md

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ If you liked the project or if `netcorekit` helped you, please give a star so th
1515
### Features
1616

1717
- [x] Simple libraries. No frameworks. Little abstraction.
18-
- [x] Opt-in and out of the box [features](https://github.com/cloudnative-netcore/netcorekit/wiki/Miniservice-template-guidance) with [Feature Toggles](https://martinfowler.com/articles/feature-toggles.html) technique.
18+
- [x] Opt-in and out of the box [features](https://github.com/cloudnative-netcore/netcorekit/wiki/Host-template-guidance) with [Feature Toggles](https://martinfowler.com/articles/feature-toggles.html) technique.
1919
- [x] Adhere to [twelve-factor app paradigm](https://12factor.net) and more.
2020
- [x] Authentication/Authorization with OAuth 2.0 and OpenID Connect.
2121
- [x] [Domain-driven Design](https://en.wikipedia.org/wiki/Domain-driven_design) in mind.
@@ -35,7 +35,7 @@ Small, lightweight, cloud-native out of the box, and much more simple to get sta
3535

3636
### Look how simple we can start as below:
3737

38-
- Standard template - NetCoreKit.Template.Standard: without storage, merely calculation and job tasks:
38+
- **Standard template - NetCoreKit.Template.Standard**: without storage, merely calculation and job tasks:
3939

4040
```csharp
4141
public class Startup
@@ -52,7 +52,7 @@ public class Startup
5252
}
5353
```
5454

55-
- EfCore template - NetCoreKit.Template.EfCore: with Entity Framework Core (SQL Server, MySQL, and SQLite providers) comes along with the generic repository in place:
55+
- **EfCore template - NetCoreKit.Template.EfCore**: with Entity Framework Core (SQL Server, MySQL, and SQLite providers) comes along with the generic repository in place:
5656

5757
```csharp
5858
public class Startup
@@ -69,7 +69,9 @@ public class Startup
6969
}
7070
```
7171

72-
- MongoDb template - NetCoreKit.Template.MongoDb: with NoSQL (MongoDb provider) comes along with the generic repository in place:
72+
> EfCore template usage can be found at [TodoApi Sample](https://github.com/cloudnative-netcore/netcorekit/tree/master/samples/TodoApi).
73+
74+
- **MongoDb template - NetCoreKit.Template.MongoDb**: with NoSQL (MongoDb provider) comes along with the generic repository in place:
7375

7476
```csharp
7577
public class Startup
@@ -86,8 +88,9 @@ public class Startup
8688
}
8789
```
8890

91+
> MongoDb template usage can be found at [BiMonetaryApi Sample](https://github.com/cloudnative-netcore/netcorekit/tree/master/samples/BiMonetaryApi).
92+
8993
- Read [Get starting](https://github.com/cloudnative-netcore/netcorekit/wiki/Get-Started) section and [Play with Kubernetes](https://github.com/cloudnative-netcore/netcorekit/wiki/Deploy-on-k8s-on-local) section to know more about this cloud-native toolkit.
90-
- Basic usage can be found at [TodoApi Sample](https://github.com/cloudnative-netcore/netcorekit/tree/master/samples/TodoApi)
9194
- More advance usage is at [Coolstore Microservices](https://github.com/vietnam-devs/coolstore-microservices) project.
9295

9396
### Contributing

build.cake

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@ var libs = new List<string>{
1313
"./src/NetCoreKit.Infrastructure/NetCoreKit.Infrastructure.csproj",
1414
"./src/NetCoreKit.Infrastructure.AspNetCore/NetCoreKit.Infrastructure.AspNetCore.csproj",
1515
"./src/NetCoreKit.Infrastructure.AspNetCore.CleanArch/NetCoreKit.Infrastructure.AspNetCore.CleanArch.csproj",
16-
"./src/NetCoreKit.Infrastructure.AspNetCore.Miniservice/NetCoreKit.Infrastructure.AspNetCore.Miniservice.csproj",
1716
"./src/NetCoreKit.Infrastructure.AspNetCore.OpenApi/NetCoreKit.Infrastructure.AspNetCore.OpenApi.csproj",
1817
"./src/NetCoreKit.Infrastructure.EfCore/NetCoreKit.Infrastructure.EfCore.csproj",
1918
"./src/NetCoreKit.Infrastructure.EfCore.SqlServer/NetCoreKit.Infrastructure.EfCore.SqlServer.csproj",
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
using System.Diagnostics;
2+
using System.Reflection;
3+
using Microsoft.AspNetCore.Builder;
4+
using Microsoft.AspNetCore.Diagnostics;
5+
using Microsoft.AspNetCore.Mvc;
6+
using Microsoft.AspNetCore.Server.Kestrel.Core;
7+
using NetCoreKit.Infrastructure.AspNetCore.Rest;
8+
using NetCoreKit.Utils.Helpers;
9+
10+
namespace NetCoreKit.Infrastructure.AspNetCore.All
11+
{
12+
public static class AppBuilderExtensions
13+
{
14+
public static IApplicationBuilder UseExceptionHandlerCore(this IApplicationBuilder app)
15+
{
16+
app.UseExceptionHandler(errorApp =>
17+
{
18+
#pragma warning disable CS1998
19+
errorApp.Run(async context =>
20+
{
21+
var errorFeature = context.Features.Get<IExceptionHandlerFeature>();
22+
var exception = errorFeature.Error;
23+
24+
// the IsTrusted() extension method doesn't exist and
25+
// you should implement your own as you may want to interpret it differently
26+
// i.e. based on the current principal
27+
var problemDetails = new ProblemDetails
28+
{
29+
Instance = $"urn:myorganization:error:{IdHelper.GenerateId()}"
30+
};
31+
32+
if (exception is BadHttpRequestException badHttpRequestException)
33+
{
34+
problemDetails.Title = "Invalid request";
35+
problemDetails.Status = (int)typeof(BadHttpRequestException)
36+
.GetProperty("StatusCode", BindingFlags.NonPublic | BindingFlags.Instance)
37+
?.GetValue(badHttpRequestException);
38+
problemDetails.Detail = badHttpRequestException.Message;
39+
}
40+
else
41+
{
42+
problemDetails.Title = "An unexpected error occurred!";
43+
problemDetails.Status = 500;
44+
problemDetails.Detail = exception.Demystify().ToString();
45+
}
46+
47+
// TODO: log the exception etc..
48+
// ...
49+
50+
context.Response.StatusCode = problemDetails.Status.Value;
51+
context.Response.WriteJson(problemDetails, "application/problem+json");
52+
}
53+
#pragma warning restore CS1998
54+
);
55+
});
56+
57+
return app;
58+
}
59+
}
60+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
using Microsoft.AspNetCore.Mvc;
2+
3+
namespace NetCoreKit.Infrastructure.AspNetCore.All.Controllers
4+
{
5+
[Route("")]
6+
[ApiVersionNeutral]
7+
[ApiExplorerSettings(IgnoreApi = true)]
8+
public class ErrorController : Controller
9+
{
10+
[HttpGet("/error")]
11+
public IActionResult Index()
12+
{
13+
return new BadRequestResult();
14+
}
15+
}
16+
}

src/NetCoreKit.Infrastructure.AspNetCore/ServiceCollectionExtensions.cs renamed to src/NetCoreKit.Infrastructure.AspNetCore.All/ServiceCollectionExtensions.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
using NetCoreKit.Infrastructure.AspNetCore.Validation;
1919
using Newtonsoft.Json.Serialization;
2020

21-
namespace NetCoreKit.Infrastructure.AspNetCore
21+
namespace NetCoreKit.Infrastructure.AspNetCore.All
2222
{
2323
public static class ServiceCollectionExtensions
2424
{

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
using System.Diagnostics;
1+
/*using System.Diagnostics;
22
using System.Reflection;
33
using BeatPulse.UI;
44
using IdentityServer4.Models;
@@ -173,4 +173,4 @@ public static IApplicationBuilder UseMiniService(this IApplicationBuilder app)
173173
return app;
174174
}
175175
}
176-
}
176+
}*/

src/NetCoreKit.Infrastructure.AspNetCore.Miniservice/EfCore.ServiceCollectionExtensions.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
using System;
1+
/*using System;
22
using System.Linq;
33
using BeatPulse.Core;
44
using BeatPulse.UI;
@@ -90,4 +90,4 @@ public static IServiceCollection AddEfCoreMiniService<TDbContext>(this IServiceC
9090
return services;
9191
}
9292
}
93-
}
93+
}*/

src/NetCoreKit.Infrastructure.AspNetCore.Miniservice/Mongo.ServiceCollectionExtensions.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
using System;
1+
/*using System;
22
using BeatPulse.Core;
33
using BeatPulse.UI;
44
using Microsoft.AspNetCore.Hosting;
@@ -77,4 +77,4 @@ public static IServiceCollection AddMongoMiniService(this IServiceCollection ser
7777
return services;
7878
}
7979
}
80-
}
80+
} */

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
using System;
1+
/*using System;
22
using BeatPulse.Core;
33
using BeatPulse.UI;
44
using Microsoft.AspNetCore.Hosting;
@@ -66,4 +66,4 @@ public static IServiceCollection AddMiniService(this IServiceCollection services
6666
return services;
6767
}
6868
}
69-
}
69+
}*/

templates/NetCoreKit.Template.EfCore/AppBuilderExtensions.cs

Lines changed: 21 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,16 @@
1-
using System.Diagnostics;
21
using System.Reflection;
32
using BeatPulse.UI;
43
using IdentityServer4.Models;
54
using Microsoft.AspNetCore.Builder;
6-
using Microsoft.AspNetCore.Diagnostics;
75
using Microsoft.AspNetCore.Hosting;
8-
using Microsoft.AspNetCore.Mvc;
96
using Microsoft.AspNetCore.Mvc.ApiExplorer;
10-
using Microsoft.AspNetCore.Server.Kestrel.Core;
117
using Microsoft.Extensions.Configuration;
128
using Microsoft.Extensions.DependencyInjection;
139
using Microsoft.Extensions.Logging;
10+
using NetCoreKit.Infrastructure.AspNetCore.All;
1411
using NetCoreKit.Infrastructure.AspNetCore.Configuration;
1512
using NetCoreKit.Infrastructure.AspNetCore.Middlewares;
16-
using NetCoreKit.Infrastructure.AspNetCore.Rest;
1713
using NetCoreKit.Infrastructure.Features;
18-
using NetCoreKit.Utils.Helpers;
1914
using StackExchange.Profiling;
2015

2116
namespace NetCoreKit.Template.EfCore
@@ -29,15 +24,16 @@ public static IApplicationBuilder UseEfCoreTemplate(this IApplicationBuilder app
2924
var env = app.ApplicationServices.GetRequiredService<IHostingEnvironment>();
3025
var feature = app.ApplicationServices.GetRequiredService<IFeature>();
3126

32-
// #1
3327
loggerFactory.AddConsole(config.GetSection("Logging"));
3428
loggerFactory.AddDebug();
3529

30+
// #1 Log exception handler
3631
app.UseMiddleware<LogHandlerMiddleware>();
3732

33+
// #2 Default response cache
3834
app.UseResponseCaching();
3935

40-
// #2
36+
// #3 configure Exception handling
4137
if (env.IsDevelopment())
4238
{
4339
app.UseDeveloperExceptionPage();
@@ -48,52 +44,12 @@ public static IApplicationBuilder UseEfCoreTemplate(this IApplicationBuilder app
4844
}
4945
else
5046
{
51-
app.UseExceptionHandler("/Home/Error");
47+
app.UseExceptionHandler("/error");
5248
}
53-
54-
app.UseExceptionHandler(errorApp =>
55-
{
56-
#pragma warning disable CS1998
57-
errorApp.Run(async context =>
58-
{
59-
var errorFeature = context.Features.Get<IExceptionHandlerFeature>();
60-
var exception = errorFeature.Error;
61-
62-
// the IsTrusted() extension method doesn't exist and
63-
// you should implement your own as you may want to interpret it differently
64-
// i.e. based on the current principal
65-
var problemDetails = new ProblemDetails
66-
{
67-
Instance = $"urn:myorganization:error:{IdHelper.GenerateId()}"
68-
};
69-
70-
if (exception is BadHttpRequestException badHttpRequestException)
71-
{
72-
problemDetails.Title = "Invalid request";
73-
problemDetails.Status = (int)typeof(BadHttpRequestException)
74-
.GetProperty("StatusCode", BindingFlags.NonPublic | BindingFlags.Instance)
75-
?.GetValue(badHttpRequestException);
76-
problemDetails.Detail = badHttpRequestException.Message;
77-
}
78-
else
79-
{
80-
problemDetails.Title = "An unexpected error occurred!";
81-
problemDetails.Status = 500;
82-
problemDetails.Detail = exception.Demystify().ToString();
83-
}
84-
85-
// TODO: log the exception etc..
86-
// ...
87-
88-
context.Response.StatusCode = problemDetails.Status.Value;
89-
context.Response.WriteJson(problemDetails, "application/problem+json");
90-
}
91-
#pragma warning restore CS1998
92-
);
93-
});
94-
49+
app.UseExceptionHandlerCore();
9550
app.UseMiddleware<ErrorHandlerMiddleware>();
9651

52+
// #4 BeatPulse healthcheck and BeatPulse UI
9753
app
9854
.UseBeatPulse(options =>
9955
{
@@ -103,52 +59,49 @@ public static IApplicationBuilder UseEfCoreTemplate(this IApplicationBuilder app
10359
})
10460
.UseBeatPulseUI();
10561

62+
// #5 Miniprofiler on API
10663
if (feature.IsEnabled("OpenApi:Profiler"))
10764
app.UseMiddleware<MiniProfilerMiddleware>();
10865

109-
// #3
66+
// #6 liveness endpoint
11067
#pragma warning disable CS1998 // Async method lacks 'await' operators and will run synchronously
11168
app.Map("/liveness", lapp => lapp.Run(async ctx => ctx.Response.StatusCode = 200));
11269
#pragma warning restore CS1998 // Async method lacks 'await' operators and will run synchronously
11370

114-
// #4
71+
// #7 Re-configure the base path
11572
var basePath = config.GetBasePath();
116-
11773
if (!string.IsNullOrEmpty(basePath))
11874
{
11975
var logger = loggerFactory.CreateLogger("init");
12076
logger.LogInformation($"Using PATH BASE '{basePath}'");
12177
app.UsePathBase(basePath);
12278
}
12379

124-
// #5
80+
// #8 ForwardHeaders
12581
if (!env.IsDevelopment())
12682
app.UseForwardedHeaders();
12783

128-
// #6
84+
// #9 Cors
12985
app.UseCors("CorsPolicy");
13086

131-
// #7
87+
// #10 AuthN
13288
if (feature.IsEnabled("AuthN"))
13389
app.UseAuthentication();
13490

135-
// #8
91+
// #11 Mvc
13692
app.UseMvc();
13793

138-
// #9
139-
basePath = config.GetBasePath();
140-
var currentHostUri = config.GetExternalCurrentHostUri();
141-
94+
// #12 Open API
14295
if (feature.IsEnabled("OpenApi"))
14396
app.UseSwagger();
14497

14598
if (feature.IsEnabled("OpenApi:OpenApiUI"))
99+
{
100+
// to make it work, we need to create an application with swagger_app name
146101
app.UseSwaggerUI(
147102
c =>
148103
{
149104
var provider = app.ApplicationServices.GetRequiredService<IApiVersionDescriptionProvider>();
150-
151-
// build a swagger endpoint for each discovered API version
152105
foreach (var description in provider.ApiVersionDescriptions)
153106
c.SwaggerEndpoint(
154107
$"{basePath}swagger/{description.GroupName}/swagger.json",
@@ -159,16 +112,17 @@ public static IApplicationBuilder UseEfCoreTemplate(this IApplicationBuilder app
159112
c.OAuthClientId("swagger_id");
160113
c.OAuthClientSecret("secret".Sha256());
161114
c.OAuthAppName("swagger_app");
162-
c.OAuth2RedirectUrl($"{currentHostUri}/swagger/oauth2-redirect.html");
115+
c.OAuth2RedirectUrl($"{config.GetExternalCurrentHostUri()}/swagger/oauth2-redirect.html");
163116
}
164117

165118
if (feature.IsEnabled("OpenApi:Profiler"))
166119
c.IndexStream = () =>
167-
typeof(Infrastructure.AspNetCore.ServiceCollectionExtensions)
120+
typeof(Infrastructure.AspNetCore.All.ServiceCollectionExtensions)
168121
.GetTypeInfo()
169122
.Assembly
170-
.GetManifestResourceStream("NetCoreKit.Infrastructure.AspNetCore.Miniservice.Swagger.index.html");
123+
.GetManifestResourceStream("NetCoreKit.Infrastructure.AspNetCore.All.Swagger.index.html");
171124
});
125+
}
172126

173127
return app;
174128
}

0 commit comments

Comments
 (0)