2
0

Use a local SQLite3 backend instead of PostgreSQL Docker container.

* The provided SQLite3 database contains the required schemas, but no data and can be reset to if required.
* Remove all references to PostgreSQL in documentation and configuration.
* Replace native sqlite3 command with a console app to remove dependency on SQLite3 installation.
This commit is contained in:
2025-11-03 15:09:09 +01:00
parent b61e6a6cc7
commit f1c0021ad3
14 changed files with 124 additions and 139 deletions

View File

@@ -1,4 +0,0 @@
Dockerfile
docker-compose.yaml
[b|B]in
[O|o]bj

View File

@@ -1,8 +0,0 @@
# Normally, we would use a multi-stage build, but for simplicity, we are using a single stage here.
FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
WORKDIR /src
COPY . .
RUN dotnet restore \
&& dotnet publish -c release -o /app
WORKDIR /app
ENTRYPOINT ["dotnet", "service.dll"]

View File

@@ -7,7 +7,7 @@ This exercise is designed to test your skills in C# and .NET.
* .NET 8.0 / C# * .NET 8.0 / C#
* Minimal ASP.NET Core Web API * Minimal ASP.NET Core Web API
* Entity Framework Core * Entity Framework Core
* PostgreSQL Database (Docker) * SQLite3 Database (simplified for portability)
* HttpClient for downstream REST API calls * HttpClient for downstream REST API calls
* ??? * ???
@@ -49,15 +49,11 @@ sequenceDiagram
**Success Criteria: Verify that the post has been saved with the database with:** **Success Criteria: Verify that the post has been saved with the database with:**
```bash ```bash
$ docker compose exec --env PGPASSWORD=password db psql -h localhost -U user --db mydatabase -c "select * from posts;" $ dotnet run --project show-posts/
id | user_id | title | body | updated_at | Id | UserId | Title | Body | UpdatedAt |
----+---------+----------------------------------------------------------------------------+-----------------------------------------------------+------------------------ | -- | ------ | -------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------- |
1 | 1 | sunt aut facere repellat provident occaecati excepturi optio reprehenderit | quia et suscipit +| 1970-01-01 00:00:00+00 | 1 | 1 | sunt aut facere repellat provident occaecati excepturi optio reprehenderit | quia et suscipit suscipit recusandae consequuntur expedita et cum reprehenderit molestiae ut ut quas totam nostrum rerum est autem sunt rem eveniet architecto | 1/1/1970 12:00:00AM +00:00 |
| | | suscipit recusandae consequuntur expedita et cum +|
| | | reprehenderit molestiae ut ut quas totam +|
| | | nostrum rerum est autem sunt rem eveniet architecto |
(1 row)
``` ```
### Phase 2 ### Phase 2
@@ -105,34 +101,10 @@ $ docker compose exec --env PGPASSWORD=password db psql -h localhost -U user --d
## Troubleshooting ## Troubleshooting
### Start database manually
Open a terminal at the repo root and execute
```bash
$ docker compose up -d db
[+] Running 3/3
✔ Network dotnet-interview-exercise_default Created 0.0s
✔ Volume "dotnet-interview-exercise_db_data" Created 0.0s
✔ Container dotnet-interview-exercise-db-1 Started 0.1s
```
### Cleanup database ### Cleanup database
In case something went wrong, wipe and rebuild the database In case something went wrong or you want to start over, wipe the database by resetting the SQLite file.
```bash ```bash
$ docker compose down -v git restore service/service.db
[+] Running 3/3
✔ Container dotnet-interview-exercise-db-1 Removed. 0.2s
✔ Network dotnet-interview-exercise_default Removed. 0.2s
✔ Volume dotnet-interview-exercise_db_data Removed. 0.0s
$ docker compose up -d db
[+] Running 3/3
✔ Network dotnet-interview-exercise_default Created 0.0s
✔ Volume "dotnet-interview-exercise_db_data" Created 0.0s
✔ Container dotnet-interview-exercise-db-1 Started 0.1s
``` ```

View File

@@ -1,36 +0,0 @@
services:
service:
build:
context: .
dockerfile: Dockerfile
depends_on:
- db
networks:
- default
ports:
- "8080:8080"
environment:
ASPNETCORE_ENVIRONMENT: Docker
db:
image: postgres:alpine
restart: unless-stopped
networks:
- default
ports:
- "5432:5432" # Also for local development
environment:
POSTGRES_USER: user
POSTGRES_PASSWORD: password
POSTGRES_DB: mydatabase
volumes:
- db_data:/var/lib/postgresql/data
- ./dbschemas:/docker-entrypoint-initdb.d
networks:
default:
driver: bridge
volumes:
db_data:
driver: local

View File

@@ -1,38 +1,42 @@
Microsoft Visual Studio Solution File, Format Version 12.00 Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17 # Visual Studio Version 17
VisualStudioVersion = 17.0.31903.59 VisualStudioVersion = 17.0.31903.59
MinimumVisualStudioVersion = 10.0.40219.1 MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "service", "service\service.csproj", "{8572A3DF-7A4C-4552-8B30-22D794E703A6}" Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "service", "service\service.csproj", "{8572A3DF-7A4C-4552-8B30-22D794E703A6}"
EndProject EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{8EC462FD-D22E-90A8-E5CE-7E832BA40C5D}" Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{8EC462FD-D22E-90A8-E5CE-7E832BA40C5D}"
ProjectSection(SolutionItems) = preProject ProjectSection(SolutionItems) = preProject
docker-compose.yaml = docker-compose.yaml README.md = README.md
Dockerfile = Dockerfile EndProjectSection
README.md = README.md EndProject
EndProjectSection Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "dbschemas", "dbschemas", "{02EA681E-C7D8-13C7-8484-4AC65E1B71E8}"
EndProject ProjectSection(SolutionItems) = preProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "dbschemas", "dbschemas", "{02EA681E-C7D8-13C7-8484-4AC65E1B71E8}" dbschemas\01-create-posts-table.sql = dbschemas\01-create-posts-table.sql
ProjectSection(SolutionItems) = preProject dbschemas\02-posts-add-updated.sql = dbschemas\02-posts-add-updated.sql
dbschemas\01-create-posts-table.sql = dbschemas\01-create-posts-table.sql EndProjectSection
dbschemas\02-posts-add-updated.sql = dbschemas\02-posts-add-updated.sql EndProject
EndProjectSection Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "show-posts", "show-posts\show-posts.csproj", "{D73F984F-F3CA-4CFD-AF1A-EDE2D688294C}"
EndProject EndProject
Global Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU Release|Any CPU = Release|Any CPU
EndGlobalSection EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution GlobalSection(ProjectConfigurationPlatforms) = postSolution
{8572A3DF-7A4C-4552-8B30-22D794E703A6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {8572A3DF-7A4C-4552-8B30-22D794E703A6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{8572A3DF-7A4C-4552-8B30-22D794E703A6}.Debug|Any CPU.Build.0 = Debug|Any CPU {8572A3DF-7A4C-4552-8B30-22D794E703A6}.Debug|Any CPU.Build.0 = Debug|Any CPU
{8572A3DF-7A4C-4552-8B30-22D794E703A6}.Release|Any CPU.ActiveCfg = Release|Any CPU {8572A3DF-7A4C-4552-8B30-22D794E703A6}.Release|Any CPU.ActiveCfg = Release|Any CPU
{8572A3DF-7A4C-4552-8B30-22D794E703A6}.Release|Any CPU.Build.0 = Release|Any CPU {8572A3DF-7A4C-4552-8B30-22D794E703A6}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection {D73F984F-F3CA-4CFD-AF1A-EDE2D688294C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
GlobalSection(SolutionProperties) = preSolution {D73F984F-F3CA-4CFD-AF1A-EDE2D688294C}.Debug|Any CPU.Build.0 = Debug|Any CPU
HideSolutionNode = FALSE {D73F984F-F3CA-4CFD-AF1A-EDE2D688294C}.Release|Any CPU.ActiveCfg = Release|Any CPU
EndGlobalSection {D73F984F-F3CA-4CFD-AF1A-EDE2D688294C}.Release|Any CPU.Build.0 = Release|Any CPU
GlobalSection(ExtensibilityGlobals) = postSolution EndGlobalSection
SolutionGuid = {DD652F00-A6DC-4579-AF4C-12EA8B5C7ECC} GlobalSection(SolutionProperties) = preSolution
EndGlobalSection HideSolutionNode = FALSE
EndGlobal EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {DD652F00-A6DC-4579-AF4C-12EA8B5C7ECC}
EndGlobalSection
EndGlobal

View File

@@ -21,10 +21,9 @@ services.AddEndpointsApiExplorer();
services.AddSwaggerGen(); services.AddSwaggerGen();
services.AddDbContext<AppDbContext>(optionsBuilder => services.AddDbContext<AppDbContext>(optionsBuilder =>
{ {
// Configure the database connection string. var connectionString = builder.Configuration.GetValue<string>("SqliteConnection");
var connectionString = builder.Configuration.GetValue<string>("PostgresConnection"); Console.WriteLine($"Setting up SQLite database with {connectionString}");
Console.WriteLine($"Connecting to PostgreSQL database with connection string: {connectionString}"); optionsBuilder.UseSqlite(connectionString);
optionsBuilder.UseNpgsql(connectionString);
}); });
var httpClientBuilder = services.AddHttpClient<JsonPlaceholderClient>(); var httpClientBuilder = services.AddHttpClient<JsonPlaceholderClient>();

View File

@@ -1,3 +0,0 @@
{
"PostgresConnection": "Server=db;Database=mydatabase;User Id=user;Password=password;"
}

View File

@@ -7,5 +7,5 @@
} }
}, },
"AllowedHosts": "*", "AllowedHosts": "*",
"PostgresConnection": "Server=localhost;Database=mydatabase;User Id=user;Password=password;" "SqliteConnection": "Data Source=service.db"
} }

View File

@@ -6,15 +6,11 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="8.0.16" /> <PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="8.0.24" />
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="9.0.6" /> <PackageReference Include="Microsoft.EntityFrameworkCore" Version="9.0.13" />
<PackageReference Include="Microsoft.Extensions.Http.Resilience" Version="9.6.0" /> <PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="9.0.13" />
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="9.0.4" /> <PackageReference Include="Microsoft.Extensions.Http.Resilience" Version="9.10.0" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.6.2" /> <PackageReference Include="Swashbuckle.AspNetCore" Version="6.9.0" />
</ItemGroup> </ItemGroup>
<Target Name="PostBuild" AfterTargets="PostBuildEvent">
<Exec Command="docker compose up -d db" />
</Target>
</Project> </Project>

BIN
service/service.db Normal file

Binary file not shown.

24
show-posts/Post.cs Normal file
View File

@@ -0,0 +1,24 @@
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
[Table("posts")]
public class Post
{
[Key]
[Column("id")]
public int Id { get; set; }
[Column("user_id")]
public int UserId { get; set; }
[Column("title")]
[Required]
public string Title { get; set; } = string.Empty;
[Column("body")]
[Required]
public string Body { get; set; } = string.Empty;
[Column("updated_at")]
public DateTimeOffset UpdatedAt { get; set; } = DateTimeOffset.Parse("1970-01-01T00:00:00Z"); // TODO: Remove the default value in Phase 3.
}

View File

@@ -0,0 +1,20 @@
using Microsoft.EntityFrameworkCore;
public class PostsDbContext : DbContext
{
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
var currentDir = System.IO.Directory.GetCurrentDirectory();
int showPostsIndex = currentDir.IndexOf("show-posts");
if (showPostsIndex > -1)
{
// Running from the bin directory, get the parent of "show-posts".
currentDir = currentDir.Substring(0, showPostsIndex - 1);
}
string repoRoot = currentDir;
optionsBuilder.UseSqlite($"Data Source={repoRoot}/service/service.db;Mode=ReadOnly;");
}
public DbSet<Post> Posts { get; set; }
}

4
show-posts/Program.cs Normal file
View File

@@ -0,0 +1,4 @@
using table.lib;
using var context = new PostsDbContext();
Table<Post>.Add(context.Posts.ToList()).ToConsole();

View File

@@ -0,0 +1,17 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework>
<RootNamespace>show_posts</RootNamespace>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="9.0.13" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="9.0.13" />
<PackageReference Include="table.lib" Version="1.17.0" />
</ItemGroup>
</Project>