-
Notifications
You must be signed in to change notification settings - Fork 0
Make Solution Template Ready
Apoorv Rane edited this page Jul 1, 2022
·
6 revisions
When you create a new .NET Core project with dotnet new command it is possible to select from a list of predefined templates. This is a very handy feature, but out-of-the-box templates are not really convenient, additional changes are required afterwards to make the project fit for its purpose. In a situation where many projects with similar structures are created, such as many micro-services, a custom template is very helpful. Users can define a custom template and easily create new projects out of it. In order to convert our solution to template, we need to make some changes to our existing solution.
- Change solution, project and folder names to simpler ones like NeoBoilerplate
- Hide the .vs folder if not hidden already
- Remove user secrets and drive connection strings from appsettings
- Change names of context classes and connection strings in all the appsettings files
"ConnectionStrings": {
"ApplicationConnectionString": "",
"IdentityConnectionString": "",
"HealthCheckConnectionString": ""
}
- Remove dbProvider from appsettings
- Remove dbProvider switch case from HealthCheckExtensions, IdentityExtensions, PersistenceExtensions and DbFixture
- Add if else in .csproj for database related packages if not present
- NeoCA.Api.csproj
<!--#if (Database == "SQLite")-->
<PackageReference Include="AspNetCore.HealthChecks.Sqlite" Version="6.0.1" />
<PackageReference Include="AspNetCore.HealthChecks.UI.SQLite.Storage" Version="6.0.2" />
<!--#endif -->
<!--#if (Database == "MSSQL")-->
<PackageReference Include="AspNetCore.HealthChecks.UI.SqlServer.Storage" Version="6.0.1-rc2.4" />
<PackageReference Include="AspNetCore.HealthChecks.SqlServer" Version="6.0.1-rc2.7" />
<!--#endif -->
<!--#if (Database == "MySQL") -->
<PackageReference Include="AspNetCore.HealthChecks.MySql" Version="6.0.1-rc1.1" />
<PackageReference Include="AspNetCore.HealthChecks.UI.MySql.Storage" Version="6.0.1-rc2.4" />
<!--#endif -->
<!--#if (Database == "PGSQL") -->
<PackageReference Include="AspNetCore.HealthChecks.NpgSql" Version="6.0.1-rc2.3" />
<PackageReference Include="AspNetCore.HealthChecks.UI.PostgreSQL.Storage" Version="6.0.1-rc2.4" />
<!--#endif -->
- NeoCA.Identity.csproj
<!--#if (Database == "SQLite")-->
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="6.0.1" />
<!--#endif-->
<!--#if (Database == "MSSQL")-->
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="6.0.1" />
<!--#endif-->
<!--#if (Database == "MySQL")-->
<PackageReference Include="Pomelo.EntityFrameworkCore.MySql" Version="6.0.0" />
<!--#endif-->
<!--#if (Database == "PGSQL")-->
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="6.0.2" />
<!--#endif-->
- NeoCA.Persistence.csproj
<!--#if (Database == "SQLite")-->
<Folder Include="Migrations\SQLite\" />
<!--#endif-->
<!--#if (Database == "MSSQL")-->
<Folder Include="Migrations\MSSQL\" />
<!--#endif-->
<!--#if (Database == "MySQL")-->
<Folder Include="Migrations\MySQL\" />
<!--#endif-->
<!--#if (Database == "PGSQL")-->
<Folder Include="Migrations\PGSQL\" />
<!--#endif-->
- Add if else in HealthCheckExtensions, IdentityExtensions, PersistenceServiceRegistration and DbFixture for database
- HealthCheckExtensions.cs
//#if (Database == "MSSQL")
services.AddHealthChecks()
.AddSqlServer(configuration["ConnectionStrings:IdentityConnectionString"], tags: new[] {
"db",
"all"})
.AddUrlGroup(new Uri(configuration["API:WeatertherInfo"]), tags: new[] {
"testdemoUrl",
"all"
});
services.AddHealthChecksUI(opt =>
{
opt.SetEvaluationTimeInSeconds(15); //time in seconds between check
opt.MaximumHistoryEntriesPerEndpoint(60); //maximum history of checks
opt.SetApiMaxActiveRequests(1); //api requests concurrency
opt.AddHealthCheckEndpoint("API", "/healthz"); //map health check api
}).AddSqlServerStorage(configuration["ConnectionStrings:HealthCheckConnectionString"]);
//#endif
//#if (Database == "PGSQL")
services.AddHealthChecks()
.AddNpgSql(configuration["ConnectionStrings:IdentityConnectionString"], tags: new[] {
"db",
"all"})
.AddUrlGroup(new Uri(configuration["API:WeatertherInfo"]), tags: new[] {
"testdemoUrl",
"all"
});
services.AddHealthChecksUI(opt =>
{
opt.SetEvaluationTimeInSeconds(15); //time in seconds between check
opt.MaximumHistoryEntriesPerEndpoint(60); //maximum history of checks
opt.SetApiMaxActiveRequests(1); //api requests concurrency
opt.AddHealthCheckEndpoint("API", "/healthz"); //map health check api
}).AddPostgreSqlStorage(configuration["ConnectionStrings:HealthCheckConnectionString"]);
//#endif
//#if (Database == "MySQL")
services.AddHealthChecks()
.AddMySql(configuration["ConnectionStrings:IdentityConnectionString"], tags: new[] {
"db",
"all"})
.AddUrlGroup(new Uri(configuration["API:WeatertherInfo"]), tags: new[] {
"testdemoUrl",
"all"
});
services.AddHealthChecksUI(opt =>
{
opt.SetEvaluationTimeInSeconds(15); //time in seconds between check
opt.MaximumHistoryEntriesPerEndpoint(60); //maximum history of checks
opt.SetApiMaxActiveRequests(1); //api requests concurrency
opt.AddHealthCheckEndpoint("API", "/healthz"); //map health check api
}).AddMySqlStorage(configuration["ConnectionStrings:HealthCheckConnectionString"]);
//#endif
//#if (Database == "SQLite")
services.AddHealthChecks()
.AddSqlite(configuration["ConnectionStrings:IdentityConnectionString"], tags: new[] {
"db",
"all"})
.AddUrlGroup(new Uri(configuration["API:WeatertherInfo"]), tags: new[] {
"testdemoUrl",
"all"
});
services.AddHealthChecksUI(opt =>
{
opt.SetEvaluationTimeInSeconds(15); //time in seconds between check
opt.MaximumHistoryEntriesPerEndpoint(60); //maximum history of checks
opt.SetApiMaxActiveRequests(1); //api requests concurrency
opt.AddHealthCheckEndpoint("API", "/healthz"); //map health check api
}).AddSqliteStorage(configuration["ConnectionStrings:HealthCheckConnectionString"]);
//#endif
return services;
- IdentityExtensions.cs
//#if (Database == "MSSQL")
services.AddDbContext<IdentityDbContext>(
options => options.UseSqlServer(configuration.GetConnectionString("IdentityConnectionString"),
b => b.MigrationsAssembly(typeof(IdentityDbContext).Assembly.FullName)));
//#endif
//#if (Database == "PGSQL")
services.AddDbContext<IdentityDbContext>(
options => options.UseNpgsql(configuration.GetConnectionString("IdentityConnectionString"),
b => b.MigrationsAssembly(typeof(IdentityDbContext).Assembly.FullName)));
//#endif
//#if (Database == "MySQL")
services.AddDbContext<IdentityDbContext>(
options => options.UseMySql(configuration.GetConnectionString("IdentityConnectionString"),
new MySqlServerVersion(new Version(8, 0,11)),
b => b.MigrationsAssembly(typeof(IdentityDbContext).Assembly.FullName)));
//#endif
//#if (Database == "SQLite")
services.AddDbContext<IdentityDbContext>(
options => options.UseSqlite(configuration.GetConnectionString("IdentityConnectionString"),
b => b.MigrationsAssembly(typeof(IdentityDbContext).Assembly.FullName)));
//#endif
- PersistenceServiceRegistration.cs
//#if (Database == "MSSQL")
services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(configuration.GetConnectionString("ApplicationConnectionString")));
//#endif
//#if (Database == "PGSQL")
services.AddDbContext<ApplicationDbContext>(options =>
options.UseNpgsql(configuration.GetConnectionString("ApplicationConnectionString")));
//#endif
//#if (Database == "MySQL")
services.AddDbContext<ApplicationDbContext>(options =>
options.UseMySql(configuration.GetConnectionString("ApplicationConnectionString"),
new MySqlServerVersion(new Version(8, 0, 11))
));
//#endif
//#if (Database == "SQLite")
services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlite(configuration.GetConnectionString("ApplicationConnectionString")));
//#endif
- DbFixture.cs
//#if (Database == "MSSQL")
ApplicationConnString = $"Server=localhost,1433;Database={ApplicationDbName};User=sa;Password=2@LaiNw)PDvs^t>L!Ybt]6H^%h3U>M;TrustServerCertificate=True;";
IdentityConnString = $"Server=localhost,1433;Database={IdentityDbName};User=sa;Password=2@LaiNw)PDvs^t>L!Ybt]6H^%h3U>M;TrustServerCertificate=True;";
HealthCheckConnString = $"Server=localhost,1433;Database={HealthCheckDbName};User=sa;Password=2@LaiNw)PDvs^t>L!Ybt]6H^%h3U>M;TrustServerCertificate=True;";
applicationBuilder.UseSqlServer(ApplicationConnString);
//#if (Authentication == "Identity")
identityBuilder.UseSqlServer(IdentityConnString);
//#endif
//#endif
//#if (Database == "PGSQL")
ApplicationConnString = $"Server=localhost;Port=5430;Database={ApplicationDbName};User Id=root;Password=root;CommandTimeout = 300;";
IdentityConnString = $"Server=localhost;Port=5430;Database={IdentityDbName};User Id=root;Password=root;CommandTimeout = 300;";
HealthCheckConnString = $"Server=localhost;Port=5430;Database={HealthCheckDbName};User Id=root;Password=root;CommandTimeout = 300;";
applicationBuilder.UseNpgsql(ApplicationConnString);
//#if (Authentication == "Identity")
identityBuilder.UseNpgsql(IdentityConnString);
//#endif
//#endif
//#if (Database == "MySQL")
ApplicationConnString = $"Server=localhost;Port=3306;Database={ApplicationDbName};Userid=root;Password=root;";
IdentityConnString = $"Server=localhost;Port=3306;Database={IdentityDbName};Userid=root;Password=root;";
HealthCheckConnString = $"Server=localhost;Port=3306;Database={HealthCheckDbName};Userid=root;Password=root;";
applicationBuilder.UseMySql(ApplicationConnString, new MySqlServerVersion(new Version(8, 0, 11)));
//#if (Authentication == "Identity")
identityBuilder.UseMySql(IdentityConnString, new MySqlServerVersion(new Version(8, 0, 11)));
//#endif
//#endif
//#if (Database == "SQLite")
ApplicationConnString = $"Data Source=..//..//..//db//{ApplicationDbName}";
IdentityConnString = $"Data Source=..//..//..//db//{IdentityDbName}";
HealthCheckConnString = $"Data Source=..//..//..//db//{HealthCheckDbName}";
applicationBuilder.UseSqlite(ApplicationConnString);
//#if (Authentication == "Identity")
identityBuilder.UseSqlite(IdentityConnString);
//#endif
//#endif
- Delete UI Project if present
- Delete bin, obj folders from all the projects
- Add if else in docker-compose if not present
##if (Database == "MSSQL")
mssql:
image: "mcr.microsoft.com/mssql/server"
ports:
- "1433:1433"
environment:
SA_PASSWORD: "2@LaiNw)PDvs^t>L!Ybt]6H^%h3U>M"
ACCEPT_EULA: "Y"
networks:
- clean-network
##endif
##if (Database == "PGSQL")
postgres:
image: postgres
environment:
POSTGRES_USER: root
POSTGRES_PASSWORD: root
ports:
- "5430:5432"
networks:
- clean-network
##endif
##if (Database == "MySQL")
mysql:
image: mysql
environment:
MYSQL_ROOT_PASSWORD: root
ports:
- '3307:3307'
networks:
- clean-network
##endif
##if (Database == "SQLite")
sqlite:
image: nouchka/sqlite3:latest
stdin_open: true
tty: true
networks:
- clean-network
volumes:
##if (Communication == "REST")
- ./test/NeoBoilerplate.API.IntegrationTests/./db:/root/db/REST
##endif
##if (Communication == "GRPC")
- ./test/NeoBoilerplate.gRPC.IntegrationTests/./db:/root/db/gRPC
##endif
##endif
- Add if else in sln to add/remove projects if needed. Keep GUIDs from your sln file as they are. Also, add if else wherever you find GUIDs(right hand side ones) for the following projects.
//#if (Authentication == "Identity")
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NeoBoilerplate.Persistence.IntegrationTests", "test\NeoBoilerplate.Persistence.IntegrationTests\NeoBoilerplate.Persistence.IntegrationTests.csproj", "{152B1EBF-3CA4-46C9-AE05-8783A64BEA41}"
ProjectSection(ProjectDependencies) = postProject
{8747A220-8B36-4E4C-81CB-EA69F7D64D4F} = {8747A220-8B36-4E4C-81CB-EA69F7D64D4F}
{85390A65-02D1-410C-846B-197DF5E01168} = {85390A65-02D1-410C-846B-197DF5E01168}
{FF97E1A5-944C-4FEE-AE96-B6EA9F1E92DF} = {FF97E1A5-944C-4FEE-AE96-B6EA9F1E92DF}
{41A0BEF1-34B6-468A-83D7-4F8C6A8FB654} = {41A0BEF1-34B6-468A-83D7-4F8C6A8FB654}
EndProjectSection
EndProject
//#endif
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NeoBoilerplate.Application.UnitTests", "test\NeoBoilerplate.Application.UnitTests\NeoBoilerplate.Application.UnitTests.csproj", "{FD2A03DF-CA97-4295-B196-627E9C488FE1}"
EndProject
//#if (Authentication == "Identity")
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NeoBoilerplate.Identity.UnitTests", "test\NeoBoilerplate.Identity.UnitTests\NeoBoilerplate.Identity.UnitTests.csproj", "{C8EC46C7-1BA2-4B3D-AD75-3989231A6E9F}"
EndProject
//#endif
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NeoBoilerplate.Infrastructure.UnitTests", "test\NeoBoilerplate.Infrastructure.UnitTests\NeoBoilerplate.Infrastructure.UnitTests.csproj", "{5710746C-B4DA-4A76-9270-6AD9E13C4737}"
EndProject
//#if (Communication == "REST")
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "API", "API", "{9EC4D129-E267-4D13-BC11-7C5EF6CF196B}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NeoBoilerplate.Api", "src\API\NeoBoilerplate.Api\NeoBoilerplate.Api.csproj", "{A0630B4A-4528-4EB9-84F4-F21AF04032DE}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NeoBoilerplate.API.IntegrationTests", "test\NeoBoilerplate.API.IntegrationTests\NeoBoilerplate.API.IntegrationTests.csproj", "{0E6F31B4-22B7-4F68-9AB7-CBC1AB22CBEC}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NeoBoilerplate.API.UnitTests", "test\NeoBoilerplate.API.UnitTests\NeoBoilerplate.API.UnitTests.csproj", "{67ED70F8-67A4-4120-A30D-BA4BC597047C}"
EndProject
//#endif
//#if (Communication == "GRPC")
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "gRPC", "gRPC", "{5A3A2012-EECC-456F-B1A8-4ADF765E90B0}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NeoBoilerplate.gRPC", "src\gRPC\NeoBoilerplate.gRPC\NeoBoilerplate.gRPC.csproj", "{31B16719-E1AF-477F-9D05-6312F7C0646E}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NeoBoilerplate.gRPC.IntegrationTests", "test\NeoBoilerplate.gRPC.IntegrationTests\NeoBoilerplate.gRPC.IntegrationTests.csproj", "{F48D57BD-2E8C-43A8-9628-DE69B3844318}"
EndProject
//#endif
//#if (Authentication == "External")
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NeoBoilerplate.Auth", "src\Infrastructure\NeoBoilerplate.Auth\NeoBoilerplate.Auth.csproj", "{B52C0D38-9904-4CAB-91DD-6EBB55526902}"
EndProject
//#endif
- Change the last step in Integration Testing.yml workflow to following
- name: Test
run: dotnet test --filter FullyQualifiedName~IntegrationTests --no-build --verbosity normal
https://github.com/NeoSOFT-Technologies/netcore6-0-template/tree/main/Content