Adding database configuration #1

Merged
csimonapastore merged 8 commits from connections into main 2025-02-21 18:42:34 +01:00
24 changed files with 847 additions and 10 deletions

View File

@@ -44,12 +44,14 @@ jobs:
env: env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # Needed to get PR information, if any GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # Needed to get PR information, if any
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
SQLSERVER_DB_SERVER: ${{ secrets.SQLSERVER_DB_SERVER }}
MONGO_DB_SERVER: ${{ secrets.MONGO_DB_SERVER }}
shell: powershell shell: powershell
run: | run: |
.\.sonar\scanner\dotnet-sonarscanner begin /k:"csimonapastore_BasicDotnetTemplate" /o:"csimonapastore-github" /d:sonar.token="${{ secrets.SONAR_TOKEN }}" /d:sonar.host.url="https://sonarcloud.io" /d:sonar.cs.vscoveragexml.reportsPaths=coverage.xml .\.sonar\scanner\dotnet-sonarscanner begin /k:"csimonapastore_BasicDotnetTemplate" /o:"csimonapastore-github" /d:sonar.token="${{ secrets.SONAR_TOKEN }}" /d:sonar.host.url="https://sonarcloud.io" /d:sonar.cs.vscoveragexml.reportsPaths=coverage.xml /d:sonar.exclusions="**/Migrations/**.cs, **/Models/Database/**.cs, **/Core/Database/**.cs"
dotnet restore dotnet restore
dotnet build --no-incremental dotnet build --no-incremental
dotnet-coverage collect "dotnet test" -f xml -o "coverage.xml" dotnet-coverage collect "dotnet test" -f xml -o "coverage.xml"
dotnet test ./MainProject.Tests/MainProject.Tests.csproj --collect "Code Coverage" --results-directory "./TestResults" dotnet test ./MainProject.Tests/MainProject.Tests.csproj --collect "Code Coverage" --results-directory "./TestResults"
Get-Content -Path "coverage.xml" Get-Content -Path "coverage.xml"
.\.sonar\scanner\dotnet-sonarscanner end /d:sonar.token="${{ secrets.SONAR_TOKEN }}" .\.sonar\scanner\dotnet-sonarscanner end /d:sonar.token="${{ secrets.SONAR_TOKEN }}"

View File

@@ -6,6 +6,11 @@
"Version": "v1.0", "Version": "v1.0",
"Description": "This template contains basic configuration for a .Net 8 backend" "Description": "This template contains basic configuration for a .Net 8 backend"
}, },
"DatabaseSettings": {
"SqlServerConnectionString": "SQLSERVER_DB_SERVER",
"MongoDbConnectionString": "MONGO_DB_SERVER",
"PostgreSQLConnectionString": "POSTGRESQL_DB_SERVER"
},
"OpenApiSettings": { "OpenApiSettings": {
"TermsOfServiceUrl": "", "TermsOfServiceUrl": "",
"OpenApiContact": { "OpenApiContact": {

View File

@@ -6,6 +6,11 @@
"Version": "v1.0", "Version": "v1.0",
"Description": "This template contains basic configuration for a .Net 8 backend" "Description": "This template contains basic configuration for a .Net 8 backend"
}, },
"DatabaseSettings": {
"SqlServerConnectionString": "SQLSERVER_DB_SERVER",
"MongoDbConnectionString": "MONGO_DB_SERVER",
"PostgreSQLConnectionString": "POSTGRESQL_DB_SERVER"
},
"OpenApiSettings": { "OpenApiSettings": {
"TermsOfServiceUrl": "https://github.com/csimonapastore/BasicDotnetTemplate/blob/main/LICENSE.md", "TermsOfServiceUrl": "https://github.com/csimonapastore/BasicDotnetTemplate/blob/main/LICENSE.md",
"OpenApiContact": { "OpenApiContact": {

View File

@@ -0,0 +1,16 @@
{
"AppSettings" :
{
"Settings": {
"Name": "MainProject",
"Version": "v1.0",
"Description": "This template contains basic configuration for a .Net 8 backend"
},
"DatabaseSettings": {
"SqlServerConnectionString": "",
"MongoDbConnectionString": "",
"PostgreSQLConnectionString": ""
}
}
}

View File

@@ -231,6 +231,93 @@ public class ProgramUtils_Tests
Assert.Fail($"An exception was thrown: {ex.Message}"); Assert.Fail($"An exception was thrown: {ex.Message}");
} }
} }
[TestMethod]
public void AddSqlServerContext_Valid()
{
try
{
WebApplicationBuilder builder = WebApplication.CreateBuilder(Array.Empty<string>());
AppSettings appSettings = ProgramUtils.AddConfiguration(ref builder, System.AppDomain.CurrentDomain.BaseDirectory + "/JsonData");
ProgramUtils.AddDbContext(ref builder, appSettings);
AppSettings _appSettings = new AppSettings();
builder.Configuration.GetSection("AppSettings").Bind(_appSettings);
var areEquals = appSettings.DatabaseSettings?.SqlServerConnectionString == _appSettings.DatabaseSettings?.SqlServerConnectionString;
Assert.IsTrue(areEquals);
}
catch (Exception ex)
{
Console.WriteLine(ex.InnerException);
Assert.Fail($"An exception was thrown: {ex.Message}");
}
}
[TestMethod]
public void AddMongoDbContext_Valid()
{
try
{
WebApplicationBuilder builder = WebApplication.CreateBuilder(Array.Empty<string>());
AppSettings appSettings = ProgramUtils.AddConfiguration(ref builder, System.AppDomain.CurrentDomain.BaseDirectory + "/JsonData");
ProgramUtils.AddDbContext(ref builder, appSettings);
AppSettings _appSettings = new AppSettings();
builder.Configuration.GetSection("AppSettings").Bind(_appSettings);
var areEquals = appSettings.DatabaseSettings?.MongoDbConnectionString == _appSettings.DatabaseSettings?.MongoDbConnectionString;
Assert.IsTrue(areEquals);
}
catch (Exception ex)
{
Console.WriteLine(ex.InnerException);
Assert.Fail($"An exception was thrown: {ex.Message}");
}
}
[TestMethod]
public void AddPostgreSqlDbContext_Valid()
{
try
{
WebApplicationBuilder builder = WebApplication.CreateBuilder(Array.Empty<string>());
AppSettings appSettings = ProgramUtils.AddConfiguration(ref builder, System.AppDomain.CurrentDomain.BaseDirectory + "/JsonData");
ProgramUtils.AddDbContext(ref builder, appSettings);
AppSettings _appSettings = new AppSettings();
builder.Configuration.GetSection("AppSettings").Bind(_appSettings);
var areEquals = appSettings.DatabaseSettings?.PostgreSQLConnectionString == _appSettings.DatabaseSettings?.PostgreSQLConnectionString;
Assert.IsTrue(areEquals);
}
catch (Exception ex)
{
Console.WriteLine(ex.InnerException);
Assert.Fail($"An exception was thrown: {ex.Message}");
}
}
[TestMethod]
public void NoSqlServerContext_Empty()
{
try
{
DatabaseSettings expectedDbSettings = new DatabaseSettings()
{
SqlServerConnectionString = ""
};
WebApplicationBuilder builder = WebApplication.CreateBuilder(Array.Empty<string>());
AppSettings realAppSettings = ProgramUtils.AddConfiguration(ref builder, System.AppDomain.CurrentDomain.BaseDirectory + "/JsonData", "noApiConfigurationAppSettings.json");
ProgramUtils.AddDbContext(ref builder, realAppSettings);
var areEquals = expectedDbSettings.SqlServerConnectionString == realAppSettings.DatabaseSettings?.SqlServerConnectionString;
Console.WriteLine(realAppSettings.DatabaseSettings?.SqlServerConnectionString);
Assert.IsTrue(areEquals);
}
catch (Exception ex)
{
Console.WriteLine(ex.InnerException);
Assert.Fail($"An exception was thrown: {ex.Message}");
}
}
} }

View File

@@ -0,0 +1,26 @@
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using MongoDB.Bson;
using MongoDB.Driver;
using MongoDB.EntityFrameworkCore;
using MongoDB.EntityFrameworkCore.Extensions;
using BasicDotnetTemplate.MainProject.Models.Database.Mongo;
namespace BasicDotnetTemplate.MainProject.Core.Database
{
public class MongoDbContext : DbContext
{
public MongoDbContext(DbContextOptions<MongoDbContext> options) : base(options) { }
public DbSet<Log> Logs { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Log>().ToCollection("Logs");
}
}
}

View File

@@ -0,0 +1,18 @@
using Microsoft.EntityFrameworkCore;
using BasicDotnetTemplate.MainProject.Models.Database.SqlServer;
namespace BasicDotnetTemplate.MainProject.Core.Database
{
public class PostgreSqlDbContext : DbContext
{
public PostgreSqlDbContext(DbContextOptions<PostgreSqlDbContext> options)
: base(options)
{
}
}
}

View File

@@ -0,0 +1,20 @@
using Microsoft.EntityFrameworkCore;
using BasicDotnetTemplate.MainProject.Models.Database.SqlServer;
namespace BasicDotnetTemplate.MainProject.Core.Database
{
public class SqlServerContext : DbContext
{
public SqlServerContext(DbContextOptions<SqlServerContext> options)
: base(options)
{
}
public DbSet<User> Users { get; set; }
}
}

View File

@@ -13,9 +13,24 @@
<PrivateAssets>all</PrivateAssets> <PrivateAssets>all</PrivateAssets>
</PackageReference> </PackageReference>
<PackageReference Include="Microsoft.AspNetCore" Version="2.2.0" /> <PackageReference Include="Microsoft.AspNetCore" Version="2.2.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="9.0.1" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Abstractions" Version="9.0.1" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="8.0.8">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="8.0.8" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="8.0.8">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="Microsoft.Extensions.Hosting" Version="8.0.0" /> <PackageReference Include="Microsoft.Extensions.Hosting" Version="8.0.0" />
<PackageReference Include="MongoDB.Driver" Version="2.28.0" />
<PackageReference Include="MongoDB.EntityFrameworkCore" Version="8.1.0" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
<PackageReference Include="NLog" Version="5.2.8" /> <PackageReference Include="NLog" Version="5.2.8" />
<PackageReference Include="NLog.Extensions.Logging" Version="5.3.8" /> <PackageReference Include="NLog.Extensions.Logging" Version="5.3.8" />
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="9.0.3" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.5.0" /> <PackageReference Include="Swashbuckle.AspNetCore" Version="6.5.0" />
<PackageReference Include="Swashbuckle.AspNetCore.Annotations" Version="6.5.0" /> <PackageReference Include="Swashbuckle.AspNetCore.Annotations" Version="6.5.0" />
<PackageReference Include="Swashbuckle.AspNetCore.Filters" Version="8.0.0" /> <PackageReference Include="Swashbuckle.AspNetCore.Filters" Version="8.0.0" />

View File

@@ -0,0 +1,132 @@
// <auto-generated />
using System;
using BasicDotnetTemplate.MainProject.Core.Database;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Metadata;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
#nullable disable
namespace MainProject.Migrations
{
[DbContext(typeof(SqlServerContext))]
[Migration("20240904211920_InitialCreate")]
partial class InitialCreate
{
/// <inheritdoc />
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("ProductVersion", "8.0.8")
.HasAnnotation("Relational:MaxIdentifierLength", 128);
SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder);
modelBuilder.Entity("BasicDotnetTemplate.MainProject.Models.Database.SqlServer.Role", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
b.Property<DateTime>("CreationTime")
.HasColumnType("datetime2");
b.Property<int>("CreationUserId")
.HasColumnType("int");
b.Property<DateTime>("DeletionTime")
.HasColumnType("datetime2");
b.Property<int>("DeletionUserId")
.HasColumnType("int");
b.Property<string>("Name")
.IsRequired()
.HasColumnType("nvarchar(max)");
b.Property<DateTime>("UpdateTime")
.HasColumnType("datetime2");
b.Property<int>("UpdateUserId")
.HasColumnType("int");
b.HasKey("Id");
b.ToTable("Role");
});
modelBuilder.Entity("BasicDotnetTemplate.MainProject.Models.Database.SqlServer.User", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
b.Property<DateTime>("CreationTime")
.HasColumnType("datetime2");
b.Property<int>("CreationUserId")
.HasColumnType("int");
b.Property<DateTime>("DeletionTime")
.HasColumnType("datetime2");
b.Property<int>("DeletionUserId")
.HasColumnType("int");
b.Property<string>("Email")
.IsRequired()
.HasColumnType("nvarchar(max)");
b.Property<string>("FirstName")
.IsRequired()
.HasColumnType("nvarchar(max)");
b.Property<string>("LastName")
.IsRequired()
.HasColumnType("nvarchar(max)");
b.Property<string>("PasswordHash")
.IsRequired()
.HasColumnType("nvarchar(max)");
b.Property<int>("RoleId")
.HasColumnType("int");
b.Property<DateTime>("UpdateTime")
.HasColumnType("datetime2");
b.Property<int>("UpdateUserId")
.HasColumnType("int");
b.Property<string>("Username")
.IsRequired()
.HasColumnType("nvarchar(max)");
b.HasKey("Id");
b.HasIndex("RoleId");
b.ToTable("Users");
});
modelBuilder.Entity("BasicDotnetTemplate.MainProject.Models.Database.SqlServer.User", b =>
{
b.HasOne("BasicDotnetTemplate.MainProject.Models.Database.SqlServer.Role", "Role")
.WithMany()
.HasForeignKey("RoleId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Role");
});
#pragma warning restore 612, 618
}
}
}

View File

@@ -0,0 +1,79 @@
using System;
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace MainProject.Migrations
{
/// <inheritdoc />
public partial class InitialCreate : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.CreateTable(
name: "Role",
columns: table => new
{
Id = table.Column<int>(type: "int", nullable: false)
.Annotation("SqlServer:Identity", "1, 1"),
Name = table.Column<string>(type: "nvarchar(max)", nullable: false),
CreationTime = table.Column<DateTime>(type: "datetime2", nullable: false),
CreationUserId = table.Column<int>(type: "int", nullable: false),
UpdateTime = table.Column<DateTime>(type: "datetime2", nullable: false),
UpdateUserId = table.Column<int>(type: "int", nullable: false),
DeletionTime = table.Column<DateTime>(type: "datetime2", nullable: false),
DeletionUserId = table.Column<int>(type: "int", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_Role", x => x.Id);
});
migrationBuilder.CreateTable(
name: "Users",
columns: table => new
{
Id = table.Column<int>(type: "int", nullable: false)
.Annotation("SqlServer:Identity", "1, 1"),
Username = table.Column<string>(type: "nvarchar(max)", nullable: false),
FirstName = table.Column<string>(type: "nvarchar(max)", nullable: false),
LastName = table.Column<string>(type: "nvarchar(max)", nullable: false),
Email = table.Column<string>(type: "nvarchar(max)", nullable: false),
RoleId = table.Column<int>(type: "int", nullable: false),
PasswordHash = table.Column<string>(type: "nvarchar(max)", nullable: false),
CreationTime = table.Column<DateTime>(type: "datetime2", nullable: false),
CreationUserId = table.Column<int>(type: "int", nullable: false),
UpdateTime = table.Column<DateTime>(type: "datetime2", nullable: false),
UpdateUserId = table.Column<int>(type: "int", nullable: false),
DeletionTime = table.Column<DateTime>(type: "datetime2", nullable: false),
DeletionUserId = table.Column<int>(type: "int", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_Users", x => x.Id);
table.ForeignKey(
name: "FK_Users_Role_RoleId",
column: x => x.RoleId,
principalTable: "Role",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateIndex(
name: "IX_Users_RoleId",
table: "Users",
column: "RoleId");
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(
name: "Users");
migrationBuilder.DropTable(
name: "Role");
}
}
}

View File

@@ -0,0 +1,132 @@
// <auto-generated />
using System;
using BasicDotnetTemplate.MainProject.Core.Database;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Metadata;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
#nullable disable
namespace MainProject.Migrations
{
[DbContext(typeof(SqlServerContext))]
[Migration("20241129231345_Try")]
partial class Try
{
/// <inheritdoc />
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("ProductVersion", "8.0.8")
.HasAnnotation("Relational:MaxIdentifierLength", 128);
SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder);
modelBuilder.Entity("BasicDotnetTemplate.MainProject.Models.Database.SqlServer.Role", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
b.Property<DateTime>("CreationTime")
.HasColumnType("datetime2");
b.Property<int>("CreationUserId")
.HasColumnType("int");
b.Property<DateTime>("DeletionTime")
.HasColumnType("datetime2");
b.Property<int>("DeletionUserId")
.HasColumnType("int");
b.Property<string>("Name")
.IsRequired()
.HasColumnType("nvarchar(max)");
b.Property<DateTime>("UpdateTime")
.HasColumnType("datetime2");
b.Property<int>("UpdateUserId")
.HasColumnType("int");
b.HasKey("Id");
b.ToTable("Role");
});
modelBuilder.Entity("BasicDotnetTemplate.MainProject.Models.Database.SqlServer.User", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
b.Property<DateTime>("CreationTime")
.HasColumnType("datetime2");
b.Property<int>("CreationUserId")
.HasColumnType("int");
b.Property<DateTime>("DeletionTime")
.HasColumnType("datetime2");
b.Property<int>("DeletionUserId")
.HasColumnType("int");
b.Property<string>("Email")
.IsRequired()
.HasColumnType("nvarchar(max)");
b.Property<string>("FirstName")
.IsRequired()
.HasColumnType("nvarchar(max)");
b.Property<string>("LastName")
.IsRequired()
.HasColumnType("nvarchar(max)");
b.Property<string>("PasswordHash")
.IsRequired()
.HasColumnType("nvarchar(max)");
b.Property<int>("RoleId")
.HasColumnType("int");
b.Property<DateTime>("UpdateTime")
.HasColumnType("datetime2");
b.Property<int>("UpdateUserId")
.HasColumnType("int");
b.Property<string>("Username")
.IsRequired()
.HasColumnType("nvarchar(max)");
b.HasKey("Id");
b.HasIndex("RoleId");
b.ToTable("Users");
});
modelBuilder.Entity("BasicDotnetTemplate.MainProject.Models.Database.SqlServer.User", b =>
{
b.HasOne("BasicDotnetTemplate.MainProject.Models.Database.SqlServer.Role", "Role")
.WithMany()
.HasForeignKey("RoleId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Role");
});
#pragma warning restore 612, 618
}
}
}

View File

@@ -0,0 +1,22 @@
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace MainProject.Migrations
{
/// <inheritdoc />
public partial class Try : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
}
}
}

View File

@@ -0,0 +1,129 @@
// <auto-generated />
using System;
using BasicDotnetTemplate.MainProject.Core.Database;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Metadata;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
#nullable disable
namespace MainProject.Migrations
{
[DbContext(typeof(SqlServerContext))]
partial class SqlServerContextModelSnapshot : ModelSnapshot
{
protected override void BuildModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("ProductVersion", "8.0.8")
.HasAnnotation("Relational:MaxIdentifierLength", 128);
SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder);
modelBuilder.Entity("BasicDotnetTemplate.MainProject.Models.Database.SqlServer.Role", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
b.Property<DateTime>("CreationTime")
.HasColumnType("datetime2");
b.Property<int>("CreationUserId")
.HasColumnType("int");
b.Property<DateTime>("DeletionTime")
.HasColumnType("datetime2");
b.Property<int>("DeletionUserId")
.HasColumnType("int");
b.Property<string>("Name")
.IsRequired()
.HasColumnType("nvarchar(max)");
b.Property<DateTime>("UpdateTime")
.HasColumnType("datetime2");
b.Property<int>("UpdateUserId")
.HasColumnType("int");
b.HasKey("Id");
b.ToTable("Role");
});
modelBuilder.Entity("BasicDotnetTemplate.MainProject.Models.Database.SqlServer.User", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
b.Property<DateTime>("CreationTime")
.HasColumnType("datetime2");
b.Property<int>("CreationUserId")
.HasColumnType("int");
b.Property<DateTime>("DeletionTime")
.HasColumnType("datetime2");
b.Property<int>("DeletionUserId")
.HasColumnType("int");
b.Property<string>("Email")
.IsRequired()
.HasColumnType("nvarchar(max)");
b.Property<string>("FirstName")
.IsRequired()
.HasColumnType("nvarchar(max)");
b.Property<string>("LastName")
.IsRequired()
.HasColumnType("nvarchar(max)");
b.Property<string>("PasswordHash")
.IsRequired()
.HasColumnType("nvarchar(max)");
b.Property<int>("RoleId")
.HasColumnType("int");
b.Property<DateTime>("UpdateTime")
.HasColumnType("datetime2");
b.Property<int>("UpdateUserId")
.HasColumnType("int");
b.Property<string>("Username")
.IsRequired()
.HasColumnType("nvarchar(max)");
b.HasKey("Id");
b.HasIndex("RoleId");
b.ToTable("Users");
});
modelBuilder.Entity("BasicDotnetTemplate.MainProject.Models.Database.SqlServer.User", b =>
{
b.HasOne("BasicDotnetTemplate.MainProject.Models.Database.SqlServer.Role", "Role")
.WithMany()
.HasForeignKey("RoleId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Role");
});
#pragma warning restore 612, 618
}
}
}

View File

@@ -0,0 +1,11 @@
using MongoDB.Bson;
using MongoDB.Bson.Serialization.Attributes;
namespace BasicDotnetTemplate.MainProject.Models.Database.Mongo
{
public class Log
{
[BsonId]
public ObjectId Id { get; set; }
}
}

View File

@@ -0,0 +1,16 @@
namespace BasicDotnetTemplate.MainProject.Models.Database.SqlServer
{
public class Base
{
public int Id { get; set; }
public DateTime CreationTime { get; set; }
public int CreationUserId { get; set; }
public DateTime UpdateTime { get; set; }
public int UpdateUserId { get; set; }
public DateTime DeletionTime { get; set; }
public int DeletionUserId { get; set; }
}
}

View File

@@ -0,0 +1,12 @@
using System.Text.Json.Serialization;
namespace BasicDotnetTemplate.MainProject.Models.Database.SqlServer
{
public class Role : Base
{
public required string Name { get; set; }
}
}

View File

@@ -0,0 +1,19 @@
using System.Text.Json.Serialization;
namespace BasicDotnetTemplate.MainProject.Models.Database.SqlServer
{
public class User : Base
{
public required string Username { get; set; }
public required string FirstName { get; set; }
public required string LastName { get; set; }
public required string Email { get; set; }
public required Role Role { get; set; }
[JsonIgnore]
public required string PasswordHash { get; set; }
}
}

View File

@@ -6,6 +6,7 @@ public class AppSettings
public Settings? Settings { get; set; } public Settings? Settings { get; set; }
public PrivateSettings? PrivateSettings { get; set; } public PrivateSettings? PrivateSettings { get; set; }
public OpenApiSettings? OpenApiSettings { get; set; } public OpenApiSettings? OpenApiSettings { get; set; }
public DatabaseSettings? DatabaseSettings { get; set; }
#nullable disable #nullable disable
} }

View File

@@ -0,0 +1,10 @@
namespace BasicDotnetTemplate.MainProject.Models.Settings;
public class DatabaseSettings
{
#nullable enable
public string? SqlServerConnectionString { get; set; }
public string? MongoDbConnectionString { get; set; }
public string? PostgreSQLConnectionString { get; set; }
#nullable disable
}

View File

@@ -1,11 +1,10 @@
using System; using NLog;
using System.Runtime.CompilerServices;
using Microsoft.OpenApi.Models;
using NLog;
using BasicDotnetTemplate.MainProject.Models.Settings; using BasicDotnetTemplate.MainProject.Models.Settings;
using System.Reflection; using System.Reflection;
using BasicDotnetTemplate.MainProject.Utils; using BasicDotnetTemplate.MainProject.Utils;
namespace BasicDotnetTemplate.MainProject; namespace BasicDotnetTemplate.MainProject;
public static class ReflectionProgram public static class ReflectionProgram
@@ -40,9 +39,12 @@ internal static class Program
AppSettings appSettings = ProgramUtils.AddConfiguration(ref builder); AppSettings appSettings = ProgramUtils.AddConfiguration(ref builder);
ProgramUtils.AddServices(ref builder); ProgramUtils.AddServices(ref builder);
ProgramUtils.AddScopes(ref builder);
ProgramUtils.AddOpenApi(ref builder, appSettings); ProgramUtils.AddOpenApi(ref builder, appSettings);
ProgramUtils.AddDbContext(ref builder, appSettings);
WebApplication app = builder.Build(); WebApplication app = builder.Build();
ProgramUtils.AddMiddlewares(ref app); ProgramUtils.AddMiddlewares(ref app);
Logger.Info("[Program][Initialize] End building"); Logger.Info("[Program][Initialize] End building");
return app; return app;
} }

View File

@@ -1,9 +1,11 @@
using System; using Microsoft.EntityFrameworkCore;
using System.Runtime.CompilerServices;
using Microsoft.OpenApi.Models; using Microsoft.OpenApi.Models;
using MongoDB.Driver;
using NLog; using NLog;
using BasicDotnetTemplate.MainProject.Core.Database;
using BasicDotnetTemplate.MainProject.Models.Settings; using BasicDotnetTemplate.MainProject.Models.Settings;
using System.Reflection;
namespace BasicDotnetTemplate.MainProject.Utils; namespace BasicDotnetTemplate.MainProject.Utils;
@@ -125,4 +127,52 @@ public static class ProgramUtils
Logger.Info("[ProgramUtils][AddMiddlewares] Done middlewares"); Logger.Info("[ProgramUtils][AddMiddlewares] Done middlewares");
} }
public static void AddDbContext(ref WebApplicationBuilder builder, AppSettings appSettings)
{
Logger.Info("[ProgramUtils][AddDbContext] Adding DbContext");
var messages = String.Empty;
if (!String.IsNullOrEmpty(appSettings.DatabaseSettings?.SqlServerConnectionString))
{
var connectionString = appSettings.DatabaseSettings?.SqlServerConnectionString ?? String.Empty;
connectionString = connectionString.Replace("SQLSERVER_DB_SERVER", Environment.GetEnvironmentVariable("SQLSERVER_DB_SERVER"));
builder.Services.AddDbContext<SqlServerContext>(options =>
options.UseSqlServer(connectionString)
);
messages = "SqlServerContext";
}
if (!String.IsNullOrEmpty(appSettings.DatabaseSettings?.MongoDbConnectionString))
{
var connectionString = appSettings.DatabaseSettings?.MongoDbConnectionString ?? String.Empty;
connectionString = connectionString.Replace("MONGO_DB_SERVER", Environment.GetEnvironmentVariable("MONGODB_DB_SERVER"));
var databaseName = connectionString.Split("/").LastOrDefault();
if (!String.IsNullOrEmpty(databaseName))
{
var client = new MongoClient(connectionString);
builder.Services.AddDbContext<MongoDbContext>(options =>
options.UseMongoDB(client, databaseName)
);
messages = messages + (String.IsNullOrEmpty(messages) ? "" : ", ") + "MongoDbContext";
}
}
if (!String.IsNullOrEmpty(appSettings.DatabaseSettings?.PostgreSQLConnectionString))
{
var connectionString = appSettings.DatabaseSettings?.PostgreSQLConnectionString ?? String.Empty;
connectionString = connectionString.Replace("POSTGRESQL_DB_SERVER", Environment.GetEnvironmentVariable("POSTGRESQL_DB_SERVER"));
builder.Services.AddDbContext<PostgreSqlDbContext>(options =>
options.UseNpgsql(connectionString)
);
messages = messages + (String.IsNullOrEmpty(messages) ? "" : ", ") + "PostgreSqlDbContext";
}
messages = String.IsNullOrEmpty(messages) ? "No context" : messages;
Logger.Info($"[ProgramUtils][AddDbContext] {messages} added");
}
public static void AddScopes(ref WebApplicationBuilder builder)
{
Logger.Info("[ProgramUtils][AddScopes] Adding scopes");
Logger.Info("[ProgramUtils][AddScopes] Done scopes");
}
} }

View File

@@ -6,6 +6,11 @@
"Version": "v1.0", "Version": "v1.0",
"Description": "This template contains basic configuration for a .Net 8 backend" "Description": "This template contains basic configuration for a .Net 8 backend"
}, },
"DatabaseSettings": {
"SqlServerConnectionString": "SQLSERVER_DB_SERVER",
"MongoDbConnectionString": "MONGO_DB_SERVER",
"PostgreSQLConnectionString": "POSTGRESQL_DB_SERVER"
},
"OpenApiSettings": { "OpenApiSettings": {
"TermsOfServiceUrl": "", "TermsOfServiceUrl": "",
"OpenApiContact": { "OpenApiContact": {
@@ -16,7 +21,12 @@
"Name": "MIT License", "Name": "MIT License",
"Url": "https://github.com/csimonapastore/BasicDotnetTemplate/blob/main/LICENSE.md" "Url": "https://github.com/csimonapastore/BasicDotnetTemplate/blob/main/LICENSE.md"
} }
},
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
} }
} }
} }

View File

@@ -5,6 +5,9 @@
- [What is BasicDotnetTemplate?](#what-is-basicdotnettemplate) - [What is BasicDotnetTemplate?](#what-is-basicdotnettemplate)
- [Technologies](#technologies) - [Technologies](#technologies)
- [Dotnet](#dotnet) - [Dotnet](#dotnet)
- [Commands](#commands)
- [Debug](#debug)
- [Entity Framework](#entity-framework)
- [Sonarcloud](#sonarcloud) - [Sonarcloud](#sonarcloud)
- [Quality gate](#quality-gate) - [Quality gate](#quality-gate)
- [Code smells](#code-smells) - [Code smells](#code-smells)
@@ -20,6 +23,20 @@ Every component is developed using **dotnet-core 8.0.201** and was generated wit
> .NET is the free, open-source, cross-platform framework for building modern apps and powerful cloud services. Supported on Windows, Linux, and macOS. > .NET is the free, open-source, cross-platform framework for building modern apps and powerful cloud services. Supported on Windows, Linux, and macOS.
#### Commands
##### Debug
You can use the following comands in the MainProject folder.
```bash
dotnet watch run
```
Restarts or hot reloads the specified application, or runs a specified dotnet command, when changes in source code are detected.
### Entity Framework
This project uses Entity Framework Core, you can find the official documentation [here](https://www.entityframeworktutorial.net/efcore/entity-framework-core.aspx).
> Entity Framework is an Object/Relational Mapping (O/RM) framework. It is an enhancement to ADO.NET that gives developers an automated mechanism for accessing & storing the data in the database.
> EF Core supports two development approaches 1) Code-First 2) Database-First.
> In the code-first approach, EF Core API creates the database and tables using migration based on the conventions and configuration provided in your domain classes. This approach is useful in Domain Driven Design (DDD).
### Sonarcloud ### Sonarcloud
[![SonarCloud](https://sonarcloud.io/images/project_badges/sonarcloud-white.svg)](https://sonarcloud.io/summary/new_code?id=csimonapastore_BasicDotnetTemplate) [![SonarCloud](https://sonarcloud.io/images/project_badges/sonarcloud-white.svg)](https://sonarcloud.io/summary/new_code?id=csimonapastore_BasicDotnetTemplate)
@@ -49,3 +66,4 @@ This project uses **Sonar way** quality gate:
> >