Skip to content

Commit ab8a697

Browse files
authored
Merge pull request #18 from kapozade/feature/#11
Feature/#11
2 parents dc04ba3 + f4cd522 commit ab8a697

18 files changed

+133
-48
lines changed

README.md

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -48,11 +48,13 @@ public async Task<IActionResult> GetAsync([FromRoute] long id,
4848

4949
* You can enable open telemetry (Check [Template Options](https://github.com/kapozade/dotnet-api-template#template-options)).
5050

51+
* You can define database option by selecting one of the choice. (Check [Template Options](https://github.com/kapozade/dotnet-api-template#template-options)). Current options are PostgreSQL and MySQL. Default value is MySQL.
52+
5153
## Requirements
5254
The basic template depends on below resources.
5355

5456
* .NET7
55-
* MySQL
57+
* MySQL or PostgreSQL (depending on your choice)
5658
* Redis
5759

5860
If you would like to add outbox pattern functionality, you are required to have
@@ -74,7 +76,7 @@ Run
7476

7577
```bash
7678
## dotnet new supremeapi [options] [template options]
77-
dotnet new supremeapi -n "MyService" -eop -eot -erl
79+
dotnet new supremeapi -n "MyService" -eop -eot -erl -db mysql
7880
```
7981

8082
## Template Options
@@ -85,6 +87,7 @@ dotnet new supremeapi -n "MyService" -eop -eot -erl
8587
| -eop, --enable-outbox-pattern | Enables outbox pattern by using [CAP](https://cap.dotnetcore.xyz/) |
8688
| -eot, --enable-open-telemetry | Adds open telemetry configuration with Jaeger support |
8789
| -erl, --enable-rate-limiting | Adds basic rate limiting action filters that uses Redis behind |
90+
| -db, --database | The target database. mysql and postgres are supported. Default value is mysql |
8891

8992
## Contributors
9093

@@ -95,8 +98,9 @@ dotnet new supremeapi -n "MyService" -eop -eot -erl
9598
* Ardalis.Specification
9699
* EasyCaching
97100
* FluentValidation
98-
* DotNetCore.CAP
101+
* DotNetCore.CAP with RabbitMQ and MySQL or PostgreSQL (depending on your choice)
99102
* MediatR
103+
* Npgsql.EntityFrameworkCore.PostgreSQL
100104
* OpenTelemetry
101105
* Pomelo.EntityFrameworkCore
102106
* Scrutor

SupremeDotnetApiTemplate.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
<PropertyGroup>
44
<PackageType>Template</PackageType>
5-
<PackageVersion>1.2.0-rc.2</PackageVersion>
5+
<PackageVersion>1.2.0</PackageVersion>
66
<PackageId>Supreme.Dotnet.Api.Template</PackageId>
77
<Title>Supreme API Template</Title>
88
<Authors>Onur Kapçık</Authors>
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
{
2+
"$schema": "http://json.schemastore.org/dotnetcli.host",
3+
"symbolInfo":
4+
{
5+
"database": {
6+
"longName": "database",
7+
"shortName": "db"
8+
},
9+
"enable-outbox-pattern": {
10+
"longName": "enable-outbox-pattern",
11+
"shortName": "eop"
12+
},
13+
"enable-open-telemetry": {
14+
"longName": "enable-open-telemetry",
15+
"shortName": "eot"
16+
},
17+
"enable-rate-limiting": {
18+
"longName": "enable-rate-limiting",
19+
"shortName": "erl"
20+
}
21+
}
22+
}

templates/api/.template.config/template.json

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,16 @@
2222
"defaultValue": "net7.0",
2323
"replaces": "{TargetFramework}"
2424
},
25+
"database": {
26+
"type": "parameter",
27+
"description": "The target database",
28+
"datatype": "choice",
29+
"choices": [
30+
{"choice": "mysql", "displayName": "mysql"},
31+
{"choice": "postgres", "displayName": "postgres"}
32+
],
33+
"defaultValue": "mysql"
34+
},
2535
"enable-outbox-pattern":{
2636
"type": "parameter",
2737
"description": "Enables outbox pattern with CAP.",

templates/api/Directory.Build.targets

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@
1717
<PackageReference Update="Microsoft.Extensions.Diagnostics.HealthChecks" Version="7.0.8" />
1818
<PackageReference Update="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="7.0.5"/>
1919
<PackageReference Update="Microsoft.CodeAnalysis.CSharp.CodeStyle" Version="4.5.0" />
20-
<PackageReference Update="Pomelo.EntityFrameworkCore.MySql" Version="7.0.0" />
2120
<PackageReference Update="Swashbuckle.AspNetCore" Version="6.5.0" />
2221
<PackageReference Update="Scrutor" Version="4.2.2"/>
2322
<PackageReference Update="Serilog" Version="2.12.0" />
@@ -29,16 +28,28 @@
2928
<PackageReference Update="Moq" Version="4.18.4" />
3029
<PackageReference Update="xunit" Version="2.4.2" />
3130
<PackageReference Update="xunit.runner.visualstudio" Version="2.4.5" />
31+
</ItemGroup>
3232

33+
<ItemGroup Condition="'$(database)' == 'mysql'">
34+
<PackageReference Update="Pomelo.EntityFrameworkCore.MySql" Version="7.0.0" />
35+
</ItemGroup>
36+
<ItemGroup Condition="'$(database)' == 'postgres'">
37+
<PackageReference Update="Npgsql.EntityFrameworkCore.PostgreSQL" Version="7.0.4" />
3338
</ItemGroup>
3439

3540
<ItemGroup Condition="$(enable-outbox-pattern)">
3641
<PackageReference Update="DotNetCore.CAP" Version="7.1.2" />
3742
<PackageReference Update="DotNetCore.CAP.RabbitMQ" Version="7.1.2" />
38-
<PackageReference Update="DotNetCore.CAP.MySql" Version="7.1.2" />
3943
<PackageReference Update="DotNetCore.CAP.Dashboard" Version="7.1.2" />
4044
</ItemGroup>
4145

46+
<ItemGroup Condition="'$(database)' == 'mysql' And $(enable-outbox-pattern)">
47+
<PackageReference Update="DotNetCore.CAP.MySql" Version="7.1.2" />
48+
</ItemGroup>
49+
<ItemGroup Condition="'$(database)' == 'postgres' And $(enable-outbox-pattern)">
50+
<PackageReference Update="DotNetCore.CAP.PostgreSql" Version="7.1.2" />
51+
</ItemGroup>
52+
4253
<ItemGroup Condition="$(enable-open-telemetry)">
4354
<PackageReference Update="OpenTelemetry" Version="1.4.0" />
4455
<PackageReference Update="OpenTelemetry.Api" Version="1.4.0" />
@@ -50,7 +61,6 @@
5061
<PackageReference Update="OpenTelemetry.Instrumentation.Http" Version="1.0.0-rc9.14" />
5162
<PackageReference Update="OpenTelemetry.Instrumentation.SqlClient" Version="1.0.0-rc9.14" />
5263
</ItemGroup>
53-
5464
<ItemGroup Condition="$(enable-rate-limiting)">
5565
<PackageReference Update="StackExchange.Redis" Version="2.6.111" />
5666
</ItemGroup>

templates/api/README.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
* <b>.NET7</b>
66
* <b>Redis</b>
7-
* <b>MySQL</b>
7+
* <b>MySQL or Postgres</b> (depending on your choice)
88
* <b>Docker</b>
99

1010
## How-to
@@ -27,7 +27,7 @@ Executing migrations and db update requires a working database. You can create a
2727
<br/>
2828

2929
```bash
30-
docker compose up -d mysql
30+
docker compose up -d database
3131
````
3232

3333
<i>Note: Before running below commands, be aware that those commands require `dotnet-ef` that should have already been installed globally. <br/>
@@ -70,7 +70,7 @@ Before running the app, make sure that all dependencies are up & running.
7070
```bash
7171
docker compose up -d rabbitmq # If you didn't enable outbox pattern, you can skip this command.
7272
docker compose up -d jaeger # If you didn't enable open telemetry, you can skip this command.
73-
docker compose up -d mysql # Skip this if you already run this for Step #2.
73+
docker compose up -d database # Skip this if you already run this for Step #2.
7474
docker compose up -d redis
7575
docker compose up -d app
7676
```

templates/api/container/Dockerfile.app

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ RUN apt-get update && \
2929
rm -rf /var/lib/apt/lists/*
3030

3131
ENV ASPNETCORE_ENVIRONMENT=staging
32-
ENV DB_SERVER=mysql
32+
ENV DB_SERVER=database
3333
ENV DB_NAME=Supreme
3434
ENV DB_USER=sqlsa
3535
ENV DB_PASSWORD=SuperPass1

templates/api/docker-compose.yml

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,15 +8,16 @@ services:
88
- "5000:5000"
99
depends_on:
1010
- redis
11-
- mysql
11+
- database
1212
//#if (enable-outbox-pattern)
1313
- rabbitmq
1414
//#endif
1515
//#if (enable-open-telemetry)
1616
- jaeger
1717
//#endif
1818

19-
mysql:
19+
database:
20+
//#if (database == "mysql")
2021
image: mysql:8.0
2122
container_name: mysql
2223
command: mysqld --default-authentication-plugin=mysql_native_password --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci
@@ -27,6 +28,17 @@ services:
2728
- MYSQL_USER=sqlsa
2829
- MYSQL_PASSWORD=SuperPass1
2930
- MYSQL_DATABASE=Supreme
31+
//#endif
32+
//#if (database == "postgres")
33+
image: postgres:latest
34+
container_name: postgres
35+
environment:
36+
- POSTGRES_USER=sqlsa
37+
- POSTGRES_PASSWORD=SuperPass1
38+
- POSTGRES_DB=Supreme
39+
ports:
40+
- "5432:5432"
41+
//#endif
3042

3143
redis:
3244
image: redis

templates/api/src/Supreme.Api/appsettings.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
{
22
"ConnectionStrings": {
3+
//#if (database == "mysql")
34
"DatabaseConnection": "Server=localhost;database=Supreme;uid=root;pwd=root;Convert Zero Datetime=True;Connection Timeout=15;"
5+
//#endif
6+
//#if (database == "postgres")
7+
"DatabaseConnection": "User ID=sqlsa;Password=SuperPass1;Server=localhost;Port=5432;Database=Supreme;Integrated Security=true; Pooling=true;Timeout=15"
8+
//#endif
49
},
510
"Serilog": {
611
"MinimumLevel": "Information",

templates/api/src/Supreme.Api/appsettings.json.tmpl

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
{
22
"ConnectionStrings": {
3+
//#if (database == "mysql")
34
"DatabaseConnection": "Server=$DB_SERVER;database=$DB_NAME;uid=$DB_USER;pwd=$DB_PASSWORD;Convert Zero Datetime=True;Connection Timeout=$DB_CONNECTION_TIMEOUT;"
5+
//#endif
6+
//#if (database == "postgres")
7+
"DatabaseConnection": "User ID=$DB_USER;Password=$DB_PASSWORD;Server=$DB_SERVER;Port=5432;Database=$DB_NAME;Integrated Security=true;Pooling=true;Timeout=$DB_CONNECTION_TIMEOUT"
8+
//#endif
49
},
510
"Serilog": {
611
"MinimumLevel": "Information",

templates/api/src/Supreme.Application/FooUseCases/CommandHandlers/CreateFooCommandHandler.cs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
using Supreme.Application.FooUseCases.Commands;
22
using Supreme.Domain.Entities.Foo;
3-
using Supreme.Domain.Factories;
43
using Supreme.Domain.Db;
54
using MediatR;
65

@@ -19,7 +18,7 @@ IUnitOfWork unitOfWork
1918

2019
public async Task<CreateFooCommandResult> Handle(CreateFooCommand request, CancellationToken cancellationToken)
2120
{
22-
var foo = Foo.Create(request.Name, request.ExecutedBy, DateTimeFactory.Now());
21+
var foo = Foo.Create(request.Name, request.ExecutedBy, DateTime.UtcNow);
2322
await _unitOfWork.FooRepository.AddAsync(foo, cancellationToken);
2423
await _unitOfWork.CommitChangesAsync(cancellationToken);
2524

templates/api/src/Supreme.Application/Supreme.Application.csproj

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
<TargetFramework>{TargetFramework}</TargetFramework>
66
<ImplicitUsings>enable</ImplicitUsings>
77
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
8-
<GenerateDocumentationFile>true</GenerateDocumentationFile>
98
</PropertyGroup>
109

1110
<ItemGroup>

templates/api/src/Supreme.Domain/Factories/DateTimeFactory.cs

Lines changed: 0 additions & 9 deletions
This file was deleted.

templates/api/src/Supreme.Domain/SeedWork/BaseEntity.cs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
using Supreme.Domain.DomainEvents;
2-
using Supreme.Domain.Factories;
32
using System.Collections.Concurrent;
43

54
namespace Supreme.Domain.SeedWork;
@@ -23,7 +22,7 @@ protected BaseEntity() { }
2322
protected void SetModificationAudit(int executedBy, DateTime? executedOn = null)
2423
{
2524
ModifiedBy = executedBy;
26-
ModifiedOn = executedOn ?? DateTimeFactory.Now();
25+
ModifiedOn = executedOn ?? DateTime.UtcNow;
2726
}
2827

2928
protected void AddEvent(IDomainEvent @event)

templates/api/src/Supreme.Domain/Supreme.Domain.csproj

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
<TargetFramework>{TargetFramework}</TargetFramework>
66
<ImplicitUsings>enable</ImplicitUsings>
77
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
8-
<GenerateDocumentationFile>true</GenerateDocumentationFile>
98
<Nullable>enable</Nullable>
109
</PropertyGroup>
1110

templates/api/src/Supreme.Infrastructure/Db/RepositoryContextInjections.cs

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,15 @@ public static void AddRepositoryInjections(this IServiceCollection services, ICo
1717
var loggerFactory = serviceProvider.GetRequiredService<ILoggerFactory>();
1818
dbContextOptions.UseLoggerFactory(loggerFactory);
1919
#endif
20-
21-
dbContextOptions
20+
#if (database == "mysql")
21+
dbContextOptions
2222
.UseMySql(configuration.GetConnectionString("DatabaseConnection"),
2323
ServerVersion.AutoDetect(configuration.GetConnectionString("DatabaseConnection")));
24+
#endif
25+
#if (database == "postgres")
26+
dbContextOptions
27+
.UseNpgsql(configuration.GetConnectionString("DatabaseConnection"));
28+
#endif
2429
}
2530
);
2631

templates/api/src/Supreme.Infrastructure/Outbox/OutboxClient.cs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,12 @@
22
using Supreme.Domain.Outbox;
33
using DotNetCore.CAP;
44
using Microsoft.Extensions.DependencyInjection;
5+
#if (database == "mysql")
56
using MySqlConnector;
7+
#endif
8+
#if (database == "postgres")
9+
using Npgsql;
10+
#endif
611
using System.Data;
712

813
namespace Supreme.Infrastructure.Outbox;
@@ -30,6 +35,7 @@ public async Task AddDelayedAsync<TEvent>(TEvent @event, int delayInSeconds, Can
3035

3136
public IOutboxTransaction UseTransaction(IDbTransaction transaction)
3237
{
38+
#if (database == "mysql")
3339
if (transaction is not MySqlTransaction mySqlTransaction)
3440
{
3541
throw new DevelopmentException($"{nameof(IDbTransaction)} is not a {nameof(MySqlTransaction)}");
@@ -38,7 +44,18 @@ public IOutboxTransaction UseTransaction(IDbTransaction transaction)
3844
_capPublisher.Transaction.Value = ActivatorUtilities.CreateInstance<MySqlCapTransaction>(_capPublisher.ServiceProvider);
3945
var capTransaction = _capPublisher.Transaction.Value.Begin(mySqlTransaction, false);
4046
var capOutboxTransaction = new OutboxTransaction(capTransaction);
47+
#endif
48+
#if (database == "postgres")
49+
if (transaction is not NpgsqlTransaction postgresTransaction)
50+
{
51+
throw new DevelopmentException($"{nameof(IDbTransaction)} is not a {nameof(NpgsqlTransaction)}");
52+
}
4153

54+
_capPublisher.Transaction.Value = ActivatorUtilities.CreateInstance<PostgreSqlCapTransaction>(_capPublisher.ServiceProvider);
55+
var capTransaction = _capPublisher.Transaction.Value.Begin(postgresTransaction, false);
56+
var capOutboxTransaction = new OutboxTransaction(capTransaction);
57+
#endif
58+
4259
return capOutboxTransaction;
4360
}
4461
}

0 commit comments

Comments
 (0)