From 998a4d5ab98f3abda5dbc1c0f2af4bfdd58bd7c3 Mon Sep 17 00:00:00 2001 From: csimonapastore Date: Thu, 5 Sep 2024 01:52:07 +0200 Subject: [PATCH 1/8] Adding database configuration - wip --- MainProject/Core/Database/MongoDbContext.cs | 26 +++++++++ MainProject/Core/Database/SqlServerContext.cs | 20 +++++++ MainProject/MainProject.csproj | 15 +++++ MainProject/Models/Database/Mongo/Log.cs | 11 ++++ MainProject/Models/Database/SqlServer/Base.cs | 16 ++++++ MainProject/Models/Database/SqlServer/Role.cs | 12 ++++ MainProject/Models/Database/SqlServer/User.cs | 19 +++++++ MainProject/Models/Settings/AppSettings.cs | 1 + .../Models/Settings/DatabaseSettings.cs | 9 +++ .../Models/Settings/MongoDbSettings.cs | 9 +++ MainProject/Program.cs | 9 +-- MainProject/Utils/ProgramUtils.cs | 57 ++++++++++++++++++- MainProject/appsettings.json | 14 ++++- 13 files changed, 210 insertions(+), 8 deletions(-) create mode 100644 MainProject/Core/Database/MongoDbContext.cs create mode 100644 MainProject/Core/Database/SqlServerContext.cs create mode 100644 MainProject/Models/Database/Mongo/Log.cs create mode 100644 MainProject/Models/Database/SqlServer/Base.cs create mode 100644 MainProject/Models/Database/SqlServer/Role.cs create mode 100644 MainProject/Models/Database/SqlServer/User.cs create mode 100644 MainProject/Models/Settings/DatabaseSettings.cs create mode 100644 MainProject/Models/Settings/MongoDbSettings.cs diff --git a/MainProject/Core/Database/MongoDbContext.cs b/MainProject/Core/Database/MongoDbContext.cs new file mode 100644 index 0000000..f3ee5ca --- /dev/null +++ b/MainProject/Core/Database/MongoDbContext.cs @@ -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 options) : base(options) { } + + public DbSet Logs { get; set; } + + protected override void OnModelCreating(ModelBuilder modelBuilder) + { + modelBuilder.Entity().ToCollection("Logs"); + } + } +} + + + diff --git a/MainProject/Core/Database/SqlServerContext.cs b/MainProject/Core/Database/SqlServerContext.cs new file mode 100644 index 0000000..e9b15ab --- /dev/null +++ b/MainProject/Core/Database/SqlServerContext.cs @@ -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 options) + : base(options) + { + } + + public DbSet Users { get; set; } + } +} + + + diff --git a/MainProject/MainProject.csproj b/MainProject/MainProject.csproj index b180db7..b004205 100644 --- a/MainProject/MainProject.csproj +++ b/MainProject/MainProject.csproj @@ -13,9 +13,24 @@ all + + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + + + diff --git a/MainProject/Models/Database/Mongo/Log.cs b/MainProject/Models/Database/Mongo/Log.cs new file mode 100644 index 0000000..f3d4e92 --- /dev/null +++ b/MainProject/Models/Database/Mongo/Log.cs @@ -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; } + } +} \ No newline at end of file diff --git a/MainProject/Models/Database/SqlServer/Base.cs b/MainProject/Models/Database/SqlServer/Base.cs new file mode 100644 index 0000000..6569442 --- /dev/null +++ b/MainProject/Models/Database/SqlServer/Base.cs @@ -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; } + } +} + + + diff --git a/MainProject/Models/Database/SqlServer/Role.cs b/MainProject/Models/Database/SqlServer/Role.cs new file mode 100644 index 0000000..e5ef2f4 --- /dev/null +++ b/MainProject/Models/Database/SqlServer/Role.cs @@ -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; } + } +} + + + diff --git a/MainProject/Models/Database/SqlServer/User.cs b/MainProject/Models/Database/SqlServer/User.cs new file mode 100644 index 0000000..5f24212 --- /dev/null +++ b/MainProject/Models/Database/SqlServer/User.cs @@ -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; } + } +} + + + diff --git a/MainProject/Models/Settings/AppSettings.cs b/MainProject/Models/Settings/AppSettings.cs index 0e26c5e..86dec6d 100644 --- a/MainProject/Models/Settings/AppSettings.cs +++ b/MainProject/Models/Settings/AppSettings.cs @@ -6,6 +6,7 @@ public class AppSettings public Settings? Settings { get; set; } public PrivateSettings? PrivateSettings { get; set; } public OpenApiSettings? OpenApiSettings { get; set; } + public DatabaseSettings? DatabaseSettings { get; set; } #nullable disable } \ No newline at end of file diff --git a/MainProject/Models/Settings/DatabaseSettings.cs b/MainProject/Models/Settings/DatabaseSettings.cs new file mode 100644 index 0000000..af9fd51 --- /dev/null +++ b/MainProject/Models/Settings/DatabaseSettings.cs @@ -0,0 +1,9 @@ +namespace BasicDotnetTemplate.MainProject.Models.Settings; + +public class DatabaseSettings +{ +#nullable enable + public string? SqlServerConnectionString { get; set; } + public MongoDbSettings? MongoDbSettings { get; set; } +#nullable disable +} \ No newline at end of file diff --git a/MainProject/Models/Settings/MongoDbSettings.cs b/MainProject/Models/Settings/MongoDbSettings.cs new file mode 100644 index 0000000..042ddc6 --- /dev/null +++ b/MainProject/Models/Settings/MongoDbSettings.cs @@ -0,0 +1,9 @@ +namespace BasicDotnetTemplate.MainProject.Models.Settings; + +public class MongoDbSettings +{ +#nullable enable + public string? MongoDbConnectionString { get; set; } + public string? DatabaseName { get; set; } +#nullable disable +} \ No newline at end of file diff --git a/MainProject/Program.cs b/MainProject/Program.cs index 9edcba3..95dcd1b 100644 --- a/MainProject/Program.cs +++ b/MainProject/Program.cs @@ -1,11 +1,10 @@ -using System; -using System.Runtime.CompilerServices; -using Microsoft.OpenApi.Models; -using NLog; +using NLog; using BasicDotnetTemplate.MainProject.Models.Settings; using System.Reflection; using BasicDotnetTemplate.MainProject.Utils; + + namespace BasicDotnetTemplate.MainProject; public static class ReflectionProgram @@ -41,8 +40,10 @@ internal static class Program AppSettings appSettings = ProgramUtils.AddConfiguration(ref builder); ProgramUtils.AddServices(ref builder); ProgramUtils.AddOpenApi(ref builder, appSettings); + ProgramUtils.AddDbContext(ref builder, appSettings); WebApplication app = builder.Build(); ProgramUtils.AddMiddlewares(ref app); + Logger.Info("[Program][Initialize] End building"); return app; } diff --git a/MainProject/Utils/ProgramUtils.cs b/MainProject/Utils/ProgramUtils.cs index 701e0e0..b5424f5 100644 --- a/MainProject/Utils/ProgramUtils.cs +++ b/MainProject/Utils/ProgramUtils.cs @@ -1,9 +1,11 @@ -using System; -using System.Runtime.CompilerServices; +using Microsoft.EntityFrameworkCore; using Microsoft.OpenApi.Models; +using MongoDB.Driver; using NLog; +using BasicDotnetTemplate.MainProject.Core.Database; using BasicDotnetTemplate.MainProject.Models.Settings; -using System.Reflection; + + namespace BasicDotnetTemplate.MainProject.Utils; @@ -125,4 +127,53 @@ public static class ProgramUtils Logger.Info("[ProgramUtils][AddMiddlewares] Done middlewares"); } + public static void AddDbContext(ref WebApplicationBuilder builder, AppSettings appSettings) + { + Logger.Info("[ProgramUtils][AddDbContext] Adding DbContext"); + var databaseAdded = ""; + + var connectionString = appSettings?.DatabaseSettings?.SqlServerConnectionString ?? String.Empty; + + if (!String.IsNullOrEmpty(connectionString)) + { + connectionString = connectionString.Replace("SQLSERVER_DB_SERVER", Environment.GetEnvironmentVariable("SQLSERVER_DB_SERVER")); + connectionString = connectionString.Replace("SQLSERVER_DB_DATABASE", Environment.GetEnvironmentVariable("SQLSERVER_DB_DATABASE")); + connectionString = connectionString.Replace("SQLSERVER_DB_USER", Environment.GetEnvironmentVariable("SQLSERVER_DB_USER")); + connectionString = connectionString.Replace("SQLSERVER_DB_PASSWORD", Environment.GetEnvironmentVariable("SQLSERVER_DB_PASSWORD")); + + builder.Services.AddDbContext(options => + options.UseSqlServer(connectionString)); + + databaseAdded += "SqlServer"; + } + + + + connectionString = appSettings?.DatabaseSettings?.MongoDbSettings?.MongoDbConnectionString ?? String.Empty; + + if (!String.IsNullOrEmpty(connectionString)) + { + connectionString = connectionString.Replace("MONGODB_DB_SERVER", Environment.GetEnvironmentVariable("MONGODB_DB_SERVER")); + connectionString = connectionString.Replace("MONGODB_DB_DATABASE", Environment.GetEnvironmentVariable("MONGODB_DB_DATABASE")); + connectionString = connectionString.Replace("MONGODB_DB_USER", Environment.GetEnvironmentVariable("MONGODB_DB_USER")); + connectionString = connectionString.Replace("MONGODB_DB_PASSWORD", Environment.GetEnvironmentVariable("MONGODB_DB_PASSWORD")); + + var mongoClient = new MongoClient(connectionString); + + var databaseName = appSettings?.DatabaseSettings?.MongoDbSettings?.DatabaseName ?? Environment.GetEnvironmentVariable("MONGODB_DB_DATABASE") ?? String.Empty; + + if (!String.IsNullOrEmpty(databaseName)) + { + var dbContextOptions = new DbContextOptionsBuilder() + .UseMongoDB(mongoClient, databaseName); + } + + databaseAdded += (String.IsNullOrEmpty(databaseAdded) ? "" : ", ") + "MongoDB"; + } + + var message = String.IsNullOrEmpty(databaseAdded) ? "No DbContext added" : $"{databaseAdded} added"; + + Logger.Info($"[ProgramUtils][AddDbContext] {message}"); + } + } \ No newline at end of file diff --git a/MainProject/appsettings.json b/MainProject/appsettings.json index 0e20c40..46a5864 100644 --- a/MainProject/appsettings.json +++ b/MainProject/appsettings.json @@ -6,6 +6,13 @@ "Version": "v1.0", "Description": "This template contains basic configuration for a .Net 8 backend" }, + "DatabaseSettings": { + "SqlServerConnectionString": "Server=SQLSERVER_DB_SERVER;Initial Catalog=SQLSERVER_DB_DATABASE;User Id=SQLSERVER_DB_USER;Password=SQLSERVER_DB_PASSWORD;MultipleActiveResultSets=True;Encrypt=True;TrustServerCertificate=True;Connection Timeout=30;", + "MongoDbSettings": { + "MongoDbConnectionString": "mongodb://MONGODB_DB_USER:MONGODB_DB_PASSWORD@MONGODB_DB_SERVER:27017/MONGODB_DB_DATABASE", + "DatabaseName": "BaseDb" + } + }, "OpenApiSettings": { "TermsOfServiceUrl": "", "OpenApiContact": { @@ -16,7 +23,12 @@ "Name": "MIT License", "Url": "https://github.com/csimonapastore/BasicDotnetTemplate/blob/main/LICENSE.md" } + }, + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } } } - } \ No newline at end of file -- 2.49.1 From 0ab8d7f7d1f9307cfcc99a219fa7bbb815c28dc3 Mon Sep 17 00:00:00 2001 From: csimonapastore Date: Fri, 29 Nov 2024 22:23:40 +0100 Subject: [PATCH 2/8] Fixing connection strings - wip --- .github/workflows/build.yml | 2 ++ MainProject/Models/Settings/DatabaseSettings.cs | 2 +- MainProject/Models/Settings/MongoDbSettings.cs | 9 --------- MainProject/Utils/ProgramUtils.cs | 14 +++----------- MainProject/appsettings.json | 7 ++----- 5 files changed, 8 insertions(+), 26 deletions(-) delete mode 100644 MainProject/Models/Settings/MongoDbSettings.cs diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index e3efe2c..79f012b 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -44,6 +44,8 @@ jobs: env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # Needed to get PR information, if any SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} + SQLSERVER_DB_SERVER: ${{ secrets.SQLSERVER_DB_SERVER }} + MONGO_DB_SERVER: ${{ secrets.MONGO_DB_SERVER }} shell: powershell 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 diff --git a/MainProject/Models/Settings/DatabaseSettings.cs b/MainProject/Models/Settings/DatabaseSettings.cs index af9fd51..517d105 100644 --- a/MainProject/Models/Settings/DatabaseSettings.cs +++ b/MainProject/Models/Settings/DatabaseSettings.cs @@ -4,6 +4,6 @@ public class DatabaseSettings { #nullable enable public string? SqlServerConnectionString { get; set; } - public MongoDbSettings? MongoDbSettings { get; set; } + public string? MongoDbConnectionString { get; set; } #nullable disable } \ No newline at end of file diff --git a/MainProject/Models/Settings/MongoDbSettings.cs b/MainProject/Models/Settings/MongoDbSettings.cs deleted file mode 100644 index 042ddc6..0000000 --- a/MainProject/Models/Settings/MongoDbSettings.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace BasicDotnetTemplate.MainProject.Models.Settings; - -public class MongoDbSettings -{ -#nullable enable - public string? MongoDbConnectionString { get; set; } - public string? DatabaseName { get; set; } -#nullable disable -} \ No newline at end of file diff --git a/MainProject/Utils/ProgramUtils.cs b/MainProject/Utils/ProgramUtils.cs index b5424f5..3f67904 100644 --- a/MainProject/Utils/ProgramUtils.cs +++ b/MainProject/Utils/ProgramUtils.cs @@ -137,9 +137,6 @@ public static class ProgramUtils if (!String.IsNullOrEmpty(connectionString)) { connectionString = connectionString.Replace("SQLSERVER_DB_SERVER", Environment.GetEnvironmentVariable("SQLSERVER_DB_SERVER")); - connectionString = connectionString.Replace("SQLSERVER_DB_DATABASE", Environment.GetEnvironmentVariable("SQLSERVER_DB_DATABASE")); - connectionString = connectionString.Replace("SQLSERVER_DB_USER", Environment.GetEnvironmentVariable("SQLSERVER_DB_USER")); - connectionString = connectionString.Replace("SQLSERVER_DB_PASSWORD", Environment.GetEnvironmentVariable("SQLSERVER_DB_PASSWORD")); builder.Services.AddDbContext(options => options.UseSqlServer(connectionString)); @@ -147,20 +144,15 @@ public static class ProgramUtils databaseAdded += "SqlServer"; } - - - connectionString = appSettings?.DatabaseSettings?.MongoDbSettings?.MongoDbConnectionString ?? String.Empty; + connectionString = appSettings?.DatabaseSettings?.MongoDbConnectionString ?? String.Empty; if (!String.IsNullOrEmpty(connectionString)) { - connectionString = connectionString.Replace("MONGODB_DB_SERVER", Environment.GetEnvironmentVariable("MONGODB_DB_SERVER")); - connectionString = connectionString.Replace("MONGODB_DB_DATABASE", Environment.GetEnvironmentVariable("MONGODB_DB_DATABASE")); - connectionString = connectionString.Replace("MONGODB_DB_USER", Environment.GetEnvironmentVariable("MONGODB_DB_USER")); - connectionString = connectionString.Replace("MONGODB_DB_PASSWORD", Environment.GetEnvironmentVariable("MONGODB_DB_PASSWORD")); + connectionString = connectionString.Replace("MONGO_DB_SERVER", Environment.GetEnvironmentVariable("MONGODB_DB_SERVER")); var mongoClient = new MongoClient(connectionString); - var databaseName = appSettings?.DatabaseSettings?.MongoDbSettings?.DatabaseName ?? Environment.GetEnvironmentVariable("MONGODB_DB_DATABASE") ?? String.Empty; + var databaseName = connectionString.Split("/").LastOrDefault(); if (!String.IsNullOrEmpty(databaseName)) { diff --git a/MainProject/appsettings.json b/MainProject/appsettings.json index 46a5864..a61bba2 100644 --- a/MainProject/appsettings.json +++ b/MainProject/appsettings.json @@ -7,11 +7,8 @@ "Description": "This template contains basic configuration for a .Net 8 backend" }, "DatabaseSettings": { - "SqlServerConnectionString": "Server=SQLSERVER_DB_SERVER;Initial Catalog=SQLSERVER_DB_DATABASE;User Id=SQLSERVER_DB_USER;Password=SQLSERVER_DB_PASSWORD;MultipleActiveResultSets=True;Encrypt=True;TrustServerCertificate=True;Connection Timeout=30;", - "MongoDbSettings": { - "MongoDbConnectionString": "mongodb://MONGODB_DB_USER:MONGODB_DB_PASSWORD@MONGODB_DB_SERVER:27017/MONGODB_DB_DATABASE", - "DatabaseName": "BaseDb" - } + "SqlServerConnectionString": "SQLSERVER_DB_SERVER", + "MongoDbConnectionString": "MONGO_DB_SERVER" }, "OpenApiSettings": { "TermsOfServiceUrl": "", -- 2.49.1 From b26c553d1258c1372c20699f3fb9069f56148995 Mon Sep 17 00:00:00 2001 From: csimonapastore Date: Sat, 30 Nov 2024 00:26:05 +0100 Subject: [PATCH 3/8] Fixed multiple db contexts --- MainProject/Program.cs | 1 + MainProject/Utils/ProgramUtils.cs | 43 ++++++++++++++----------------- 2 files changed, 21 insertions(+), 23 deletions(-) diff --git a/MainProject/Program.cs b/MainProject/Program.cs index 95dcd1b..39bc52b 100644 --- a/MainProject/Program.cs +++ b/MainProject/Program.cs @@ -39,6 +39,7 @@ internal static class Program AppSettings appSettings = ProgramUtils.AddConfiguration(ref builder); ProgramUtils.AddServices(ref builder); + ProgramUtils.AddScopes(ref builder); ProgramUtils.AddOpenApi(ref builder, appSettings); ProgramUtils.AddDbContext(ref builder, appSettings); WebApplication app = builder.Build(); diff --git a/MainProject/Utils/ProgramUtils.cs b/MainProject/Utils/ProgramUtils.cs index 3f67904..42c462e 100644 --- a/MainProject/Utils/ProgramUtils.cs +++ b/MainProject/Utils/ProgramUtils.cs @@ -130,42 +130,39 @@ public static class ProgramUtils public static void AddDbContext(ref WebApplicationBuilder builder, AppSettings appSettings) { Logger.Info("[ProgramUtils][AddDbContext] Adding DbContext"); - var databaseAdded = ""; - - var connectionString = appSettings?.DatabaseSettings?.SqlServerConnectionString ?? String.Empty; - - if (!String.IsNullOrEmpty(connectionString)) + 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(options => - options.UseSqlServer(connectionString)); - - databaseAdded += "SqlServer"; + options.UseSqlServer(connectionString) + ); + messages = "SqlServerContext"; } - connectionString = appSettings?.DatabaseSettings?.MongoDbConnectionString ?? String.Empty; - - if (!String.IsNullOrEmpty(connectionString)) + 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 mongoClient = new MongoClient(connectionString); - var databaseName = connectionString.Split("/").LastOrDefault(); - if (!String.IsNullOrEmpty(databaseName)) { - var dbContextOptions = new DbContextOptionsBuilder() - .UseMongoDB(mongoClient, databaseName); + var client = new MongoClient(connectionString); + builder.Services.AddDbContext(options => + options.UseMongoDB(client, databaseName) + ); + messages = messages + (String.IsNullOrEmpty(messages) ? "" : ", ") + "MongoDbContext"; } - - databaseAdded += (String.IsNullOrEmpty(databaseAdded) ? "" : ", ") + "MongoDB"; } + messages = String.IsNullOrEmpty(messages) ? "No context" : messages; + Logger.Info($"[ProgramUtils][AddDbContext] {messages} added"); + } - var message = String.IsNullOrEmpty(databaseAdded) ? "No DbContext added" : $"{databaseAdded} added"; - - Logger.Info($"[ProgramUtils][AddDbContext] {message}"); + public static void AddScopes(ref WebApplicationBuilder builder) + { + Logger.Info("[ProgramUtils][AddScopes] Adding scopes"); + Logger.Info("[ProgramUtils][AddScopes] Done scopes"); } } \ No newline at end of file -- 2.49.1 From 8d8a7a4c77c47f4b3c378527324e7e6fc5a15740 Mon Sep 17 00:00:00 2001 From: csimonapastore Date: Sat, 30 Nov 2024 01:01:06 +0100 Subject: [PATCH 4/8] Updated README --- README.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/README.md b/README.md index 80f7a0b..6ee4270 100644 --- a/README.md +++ b/README.md @@ -8,6 +8,7 @@ - [Sonarcloud](#sonarcloud) - [Quality gate](#quality-gate) - [Code smells](#code-smells) + - [Entity Framework](#entity-framework) ## What is BasicDotnetTemplate? BasicDotnetTemplate is a basic project written in .NET 8. It contains MainProject, a WebApi project, and MainProject.Tests written in .NET 8 that contains tests for MainProject. @@ -48,4 +49,9 @@ This project uses **Sonar way** quality gate: > Code smells are usually not bugs; they are not technically incorrect and do not prevent the program from functioning. Instead, they indicate weaknesses in design that may slow down development or increase the risk of bugs or failures in the future. Bad code smells can be an indicator of factors that contribute to technical debt.[Tufano, Michele; Palomba, Fabio; Bavota, Gabriele; Oliveto, Rocco; Di Penta, Massimiliano; De Lucia, Andrea; Poshyvanyk, Denys (2015).] Robert C. Martin calls a list of code smells a "value system" for software craftsmanship.[Martin, Robert C. (2009). "17: Smells and Heuristics". Clean Code: A Handbook of Agile Software Craftsmanship. Prentice Hall.] > +### 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). -- 2.49.1 From 810f23f814305f22dc9daf4380e0b803fe3ad8a8 Mon Sep 17 00:00:00 2001 From: csimonapastore Date: Fri, 21 Feb 2025 13:21:06 +0100 Subject: [PATCH 5/8] Adding new tests --- MainProject.Tests/JsonData/appsettings.json | 5 + .../JsonData/completeAppSettings.json | 5 + .../noDbConfigurationAppSettings.json | 16 +++ MainProject.Tests/Utils/ProgramUtils_Tests.cs | 87 ++++++++++++ .../Core/Database/PostgreSqlDbContext.cs | 18 +++ MainProject/MainProject.csproj | 6 +- .../20240904211920_InitialCreate.Designer.cs | 132 ++++++++++++++++++ .../20240904211920_InitialCreate.cs | 79 +++++++++++ .../Migrations/20241129231345_Try.Designer.cs | 132 ++++++++++++++++++ MainProject/Migrations/20241129231345_Try.cs | 22 +++ .../SqlServerContextModelSnapshot.cs | 129 +++++++++++++++++ .../Models/Settings/DatabaseSettings.cs | 1 + MainProject/Utils/ProgramUtils.cs | 10 ++ MainProject/appsettings.json | 3 +- README.md | 24 +++- 15 files changed, 659 insertions(+), 10 deletions(-) create mode 100644 MainProject.Tests/JsonData/noDbConfigurationAppSettings.json create mode 100644 MainProject/Core/Database/PostgreSqlDbContext.cs create mode 100644 MainProject/Migrations/20240904211920_InitialCreate.Designer.cs create mode 100644 MainProject/Migrations/20240904211920_InitialCreate.cs create mode 100644 MainProject/Migrations/20241129231345_Try.Designer.cs create mode 100644 MainProject/Migrations/20241129231345_Try.cs create mode 100644 MainProject/Migrations/SqlServerContextModelSnapshot.cs diff --git a/MainProject.Tests/JsonData/appsettings.json b/MainProject.Tests/JsonData/appsettings.json index 0e20c40..58c3663 100644 --- a/MainProject.Tests/JsonData/appsettings.json +++ b/MainProject.Tests/JsonData/appsettings.json @@ -6,6 +6,11 @@ "Version": "v1.0", "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": { "TermsOfServiceUrl": "", "OpenApiContact": { diff --git a/MainProject.Tests/JsonData/completeAppSettings.json b/MainProject.Tests/JsonData/completeAppSettings.json index 38b0a1d..979fcf0 100644 --- a/MainProject.Tests/JsonData/completeAppSettings.json +++ b/MainProject.Tests/JsonData/completeAppSettings.json @@ -6,6 +6,11 @@ "Version": "v1.0", "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": { "TermsOfServiceUrl": "https://github.com/csimonapastore/BasicDotnetTemplate/blob/main/LICENSE.md", "OpenApiContact": { diff --git a/MainProject.Tests/JsonData/noDbConfigurationAppSettings.json b/MainProject.Tests/JsonData/noDbConfigurationAppSettings.json new file mode 100644 index 0000000..1b13ea4 --- /dev/null +++ b/MainProject.Tests/JsonData/noDbConfigurationAppSettings.json @@ -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": "" + } + } + +} \ No newline at end of file diff --git a/MainProject.Tests/Utils/ProgramUtils_Tests.cs b/MainProject.Tests/Utils/ProgramUtils_Tests.cs index 45b2581..7397366 100644 --- a/MainProject.Tests/Utils/ProgramUtils_Tests.cs +++ b/MainProject.Tests/Utils/ProgramUtils_Tests.cs @@ -231,6 +231,93 @@ public class ProgramUtils_Tests Assert.Fail($"An exception was thrown: {ex.Message}"); } } + + [TestMethod] + public void AddSqlServerContext_Valid() + { + try + { + WebApplicationBuilder builder = WebApplication.CreateBuilder(Array.Empty()); + 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()); + 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()); + 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()); + 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}"); + } + } + + } diff --git a/MainProject/Core/Database/PostgreSqlDbContext.cs b/MainProject/Core/Database/PostgreSqlDbContext.cs new file mode 100644 index 0000000..90f6acb --- /dev/null +++ b/MainProject/Core/Database/PostgreSqlDbContext.cs @@ -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 options) + : base(options) + { + } + } +} + + + diff --git a/MainProject/MainProject.csproj b/MainProject/MainProject.csproj index b004205..7aab2b7 100644 --- a/MainProject/MainProject.csproj +++ b/MainProject/MainProject.csproj @@ -13,8 +13,8 @@ all - - + + runtime; build; native; contentfiles; analyzers; buildtransitive all @@ -30,7 +30,7 @@ - + diff --git a/MainProject/Migrations/20240904211920_InitialCreate.Designer.cs b/MainProject/Migrations/20240904211920_InitialCreate.Designer.cs new file mode 100644 index 0000000..8c2d64c --- /dev/null +++ b/MainProject/Migrations/20240904211920_InitialCreate.Designer.cs @@ -0,0 +1,132 @@ +// +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 + { + /// + 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("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CreationTime") + .HasColumnType("datetime2"); + + b.Property("CreationUserId") + .HasColumnType("int"); + + b.Property("DeletionTime") + .HasColumnType("datetime2"); + + b.Property("DeletionUserId") + .HasColumnType("int"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("UpdateTime") + .HasColumnType("datetime2"); + + b.Property("UpdateUserId") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.ToTable("Role"); + }); + + modelBuilder.Entity("BasicDotnetTemplate.MainProject.Models.Database.SqlServer.User", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CreationTime") + .HasColumnType("datetime2"); + + b.Property("CreationUserId") + .HasColumnType("int"); + + b.Property("DeletionTime") + .HasColumnType("datetime2"); + + b.Property("DeletionUserId") + .HasColumnType("int"); + + b.Property("Email") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("FirstName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("LastName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("PasswordHash") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("RoleId") + .HasColumnType("int"); + + b.Property("UpdateTime") + .HasColumnType("datetime2"); + + b.Property("UpdateUserId") + .HasColumnType("int"); + + b.Property("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 + } + } +} diff --git a/MainProject/Migrations/20240904211920_InitialCreate.cs b/MainProject/Migrations/20240904211920_InitialCreate.cs new file mode 100644 index 0000000..ed4ccbc --- /dev/null +++ b/MainProject/Migrations/20240904211920_InitialCreate.cs @@ -0,0 +1,79 @@ +using System; +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace MainProject.Migrations +{ + /// + public partial class InitialCreate : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.CreateTable( + name: "Role", + columns: table => new + { + Id = table.Column(type: "int", nullable: false) + .Annotation("SqlServer:Identity", "1, 1"), + Name = table.Column(type: "nvarchar(max)", nullable: false), + CreationTime = table.Column(type: "datetime2", nullable: false), + CreationUserId = table.Column(type: "int", nullable: false), + UpdateTime = table.Column(type: "datetime2", nullable: false), + UpdateUserId = table.Column(type: "int", nullable: false), + DeletionTime = table.Column(type: "datetime2", nullable: false), + DeletionUserId = table.Column(type: "int", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_Role", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "Users", + columns: table => new + { + Id = table.Column(type: "int", nullable: false) + .Annotation("SqlServer:Identity", "1, 1"), + Username = table.Column(type: "nvarchar(max)", nullable: false), + FirstName = table.Column(type: "nvarchar(max)", nullable: false), + LastName = table.Column(type: "nvarchar(max)", nullable: false), + Email = table.Column(type: "nvarchar(max)", nullable: false), + RoleId = table.Column(type: "int", nullable: false), + PasswordHash = table.Column(type: "nvarchar(max)", nullable: false), + CreationTime = table.Column(type: "datetime2", nullable: false), + CreationUserId = table.Column(type: "int", nullable: false), + UpdateTime = table.Column(type: "datetime2", nullable: false), + UpdateUserId = table.Column(type: "int", nullable: false), + DeletionTime = table.Column(type: "datetime2", nullable: false), + DeletionUserId = table.Column(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"); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "Users"); + + migrationBuilder.DropTable( + name: "Role"); + } + } +} diff --git a/MainProject/Migrations/20241129231345_Try.Designer.cs b/MainProject/Migrations/20241129231345_Try.Designer.cs new file mode 100644 index 0000000..c301bf9 --- /dev/null +++ b/MainProject/Migrations/20241129231345_Try.Designer.cs @@ -0,0 +1,132 @@ +// +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 + { + /// + 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("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CreationTime") + .HasColumnType("datetime2"); + + b.Property("CreationUserId") + .HasColumnType("int"); + + b.Property("DeletionTime") + .HasColumnType("datetime2"); + + b.Property("DeletionUserId") + .HasColumnType("int"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("UpdateTime") + .HasColumnType("datetime2"); + + b.Property("UpdateUserId") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.ToTable("Role"); + }); + + modelBuilder.Entity("BasicDotnetTemplate.MainProject.Models.Database.SqlServer.User", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CreationTime") + .HasColumnType("datetime2"); + + b.Property("CreationUserId") + .HasColumnType("int"); + + b.Property("DeletionTime") + .HasColumnType("datetime2"); + + b.Property("DeletionUserId") + .HasColumnType("int"); + + b.Property("Email") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("FirstName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("LastName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("PasswordHash") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("RoleId") + .HasColumnType("int"); + + b.Property("UpdateTime") + .HasColumnType("datetime2"); + + b.Property("UpdateUserId") + .HasColumnType("int"); + + b.Property("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 + } + } +} diff --git a/MainProject/Migrations/20241129231345_Try.cs b/MainProject/Migrations/20241129231345_Try.cs new file mode 100644 index 0000000..46addf6 --- /dev/null +++ b/MainProject/Migrations/20241129231345_Try.cs @@ -0,0 +1,22 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace MainProject.Migrations +{ + /// + public partial class Try : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + + } + } +} diff --git a/MainProject/Migrations/SqlServerContextModelSnapshot.cs b/MainProject/Migrations/SqlServerContextModelSnapshot.cs new file mode 100644 index 0000000..90248ac --- /dev/null +++ b/MainProject/Migrations/SqlServerContextModelSnapshot.cs @@ -0,0 +1,129 @@ +// +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("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CreationTime") + .HasColumnType("datetime2"); + + b.Property("CreationUserId") + .HasColumnType("int"); + + b.Property("DeletionTime") + .HasColumnType("datetime2"); + + b.Property("DeletionUserId") + .HasColumnType("int"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("UpdateTime") + .HasColumnType("datetime2"); + + b.Property("UpdateUserId") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.ToTable("Role"); + }); + + modelBuilder.Entity("BasicDotnetTemplate.MainProject.Models.Database.SqlServer.User", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CreationTime") + .HasColumnType("datetime2"); + + b.Property("CreationUserId") + .HasColumnType("int"); + + b.Property("DeletionTime") + .HasColumnType("datetime2"); + + b.Property("DeletionUserId") + .HasColumnType("int"); + + b.Property("Email") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("FirstName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("LastName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("PasswordHash") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("RoleId") + .HasColumnType("int"); + + b.Property("UpdateTime") + .HasColumnType("datetime2"); + + b.Property("UpdateUserId") + .HasColumnType("int"); + + b.Property("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 + } + } +} diff --git a/MainProject/Models/Settings/DatabaseSettings.cs b/MainProject/Models/Settings/DatabaseSettings.cs index 517d105..3ac3be2 100644 --- a/MainProject/Models/Settings/DatabaseSettings.cs +++ b/MainProject/Models/Settings/DatabaseSettings.cs @@ -5,5 +5,6 @@ public class DatabaseSettings #nullable enable public string? SqlServerConnectionString { get; set; } public string? MongoDbConnectionString { get; set; } + public string? PostgreSQLConnectionString { get; set; } #nullable disable } \ No newline at end of file diff --git a/MainProject/Utils/ProgramUtils.cs b/MainProject/Utils/ProgramUtils.cs index 42c462e..22587c1 100644 --- a/MainProject/Utils/ProgramUtils.cs +++ b/MainProject/Utils/ProgramUtils.cs @@ -155,6 +155,16 @@ public static class ProgramUtils 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(options => + options.UseNpgsql(connectionString) + ); + messages = messages + (String.IsNullOrEmpty(messages) ? "" : ", ") + "PostgreSqlDbContext"; + } messages = String.IsNullOrEmpty(messages) ? "No context" : messages; Logger.Info($"[ProgramUtils][AddDbContext] {messages} added"); } diff --git a/MainProject/appsettings.json b/MainProject/appsettings.json index a61bba2..0fb5b09 100644 --- a/MainProject/appsettings.json +++ b/MainProject/appsettings.json @@ -8,7 +8,8 @@ }, "DatabaseSettings": { "SqlServerConnectionString": "SQLSERVER_DB_SERVER", - "MongoDbConnectionString": "MONGO_DB_SERVER" + "MongoDbConnectionString": "MONGO_DB_SERVER", + "PostgreSQLConnectionString": "POSTGRESQL_DB_SERVER" }, "OpenApiSettings": { "TermsOfServiceUrl": "", diff --git a/README.md b/README.md index 6ee4270..d7f0f0f 100644 --- a/README.md +++ b/README.md @@ -5,10 +5,12 @@ - [What is BasicDotnetTemplate?](#what-is-basicdotnettemplate) - [Technologies](#technologies) - [Dotnet](#dotnet) + - [Commands](#commands) + - [Debug](#debug) + - [Entity Framework](#entity-framework) - [Sonarcloud](#sonarcloud) - [Quality gate](#quality-gate) - [Code smells](#code-smells) - - [Entity Framework](#entity-framework) ## What is BasicDotnetTemplate? BasicDotnetTemplate is a basic project written in .NET 8. It contains MainProject, a WebApi project, and MainProject.Tests written in .NET 8 that contains tests for MainProject. @@ -21,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. +#### 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](https://sonarcloud.io/images/project_badges/sonarcloud-white.svg)](https://sonarcloud.io/summary/new_code?id=csimonapastore_BasicDotnetTemplate) @@ -49,9 +65,5 @@ This project uses **Sonar way** quality gate: > Code smells are usually not bugs; they are not technically incorrect and do not prevent the program from functioning. Instead, they indicate weaknesses in design that may slow down development or increase the risk of bugs or failures in the future. Bad code smells can be an indicator of factors that contribute to technical debt.[Tufano, Michele; Palomba, Fabio; Bavota, Gabriele; Oliveto, Rocco; Di Penta, Massimiliano; De Lucia, Andrea; Poshyvanyk, Denys (2015).] Robert C. Martin calls a list of code smells a "value system" for software craftsmanship.[Martin, Robert C. (2009). "17: Smells and Heuristics". Clean Code: A Handbook of Agile Software Craftsmanship. Prentice Hall.] > -### 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). + -- 2.49.1 From 5ef25d601f63d76fcae79ce841db959bbc118502 Mon Sep 17 00:00:00 2001 From: csimonapastore Date: Fri, 21 Feb 2025 13:55:34 +0100 Subject: [PATCH 6/8] Excluding migrations files from analysis --- .github/workflows/build.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 79f012b..42e76df 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -48,10 +48,10 @@ jobs: MONGO_DB_SERVER: ${{ secrets.MONGO_DB_SERVER }} shell: powershell 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" dotnet restore 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" Get-Content -Path "coverage.xml" .\.sonar\scanner\dotnet-sonarscanner end /d:sonar.token="${{ secrets.SONAR_TOKEN }}" -- 2.49.1 From 3ed9a15d0920807ee1b434def8cc3e768c98677e Mon Sep 17 00:00:00 2001 From: csimonapastore Date: Fri, 21 Feb 2025 18:06:53 +0100 Subject: [PATCH 7/8] Excluding database models files from analysis --- .github/workflows/build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 42e76df..9d8c917 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -48,7 +48,7 @@ jobs: MONGO_DB_SERVER: ${{ secrets.MONGO_DB_SERVER }} shell: powershell 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 /d:sonar.exclusions="**/Migrations/**.cs" + .\.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" dotnet restore dotnet build --no-incremental dotnet-coverage collect "dotnet test" -f xml -o "coverage.xml" -- 2.49.1 From aaea2c30a52773a2e002c920b513572c6d04d1e6 Mon Sep 17 00:00:00 2001 From: csimonapastore Date: Fri, 21 Feb 2025 18:20:59 +0100 Subject: [PATCH 8/8] Excluding dbcontext models files from analysis --- .github/workflows/build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 9d8c917..fa0127d 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -48,7 +48,7 @@ jobs: MONGO_DB_SERVER: ${{ secrets.MONGO_DB_SERVER }} shell: powershell 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 /d:sonar.exclusions="**/Migrations/**.cs, **/Models/Database/**.cs" + .\.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 build --no-incremental dotnet-coverage collect "dotnet test" -f xml -o "coverage.xml" -- 2.49.1