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:
@@ -1,4 +0,0 @@
|
||||
Dockerfile
|
||||
docker-compose.yaml
|
||||
[b|B]in
|
||||
[O|o]bj
|
||||
@@ -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"]
|
||||
42
README.md
42
README.md
@@ -7,7 +7,7 @@ This exercise is designed to test your skills in C# and .NET.
|
||||
* .NET 8.0 / C#
|
||||
* Minimal ASP.NET Core Web API
|
||||
* Entity Framework Core
|
||||
* PostgreSQL Database (Docker)
|
||||
* SQLite3 Database (simplified for portability)
|
||||
* HttpClient for downstream REST API calls
|
||||
* ???
|
||||
|
||||
@@ -49,15 +49,11 @@ sequenceDiagram
|
||||
**Success Criteria: Verify that the post has been saved with the database with:**
|
||||
|
||||
```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
|
||||
----+---------+----------------------------------------------------------------------------+-----------------------------------------------------+------------------------
|
||||
1 | 1 | sunt aut facere repellat provident occaecati excepturi optio reprehenderit | quia et suscipit +| 1970-01-01 00:00:00+00
|
||||
| | | suscipit recusandae consequuntur expedita et cum +|
|
||||
| | | reprehenderit molestiae ut ut quas totam +|
|
||||
| | | nostrum rerum est autem sunt rem eveniet architecto |
|
||||
(1 row)
|
||||
| Id | UserId | Title | Body | UpdatedAt |
|
||||
| -- | ------ | -------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------- |
|
||||
| 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:00 AM +00:00 |
|
||||
```
|
||||
|
||||
### Phase 2
|
||||
@@ -105,34 +101,10 @@ $ docker compose exec --env PGPASSWORD=password db psql -h localhost -U user --d
|
||||
|
||||
## 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
|
||||
|
||||
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
|
||||
$ docker compose down -v
|
||||
|
||||
[+] 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
|
||||
git restore service/service.db
|
||||
```
|
||||
|
||||
@@ -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
|
||||
80
service.sln
80
service.sln
@@ -1,38 +1,42 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 17
|
||||
VisualStudioVersion = 17.0.31903.59
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "service", "service\service.csproj", "{8572A3DF-7A4C-4552-8B30-22D794E703A6}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{8EC462FD-D22E-90A8-E5CE-7E832BA40C5D}"
|
||||
ProjectSection(SolutionItems) = preProject
|
||||
docker-compose.yaml = docker-compose.yaml
|
||||
Dockerfile = Dockerfile
|
||||
README.md = README.md
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "dbschemas", "dbschemas", "{02EA681E-C7D8-13C7-8484-4AC65E1B71E8}"
|
||||
ProjectSection(SolutionItems) = preProject
|
||||
dbschemas\01-create-posts-table.sql = dbschemas\01-create-posts-table.sql
|
||||
dbschemas\02-posts-add-updated.sql = dbschemas\02-posts-add-updated.sql
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Release|Any CPU = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{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}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{8572A3DF-7A4C-4552-8B30-22D794E703A6}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {DD652F00-A6DC-4579-AF4C-12EA8B5C7ECC}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 17
|
||||
VisualStudioVersion = 17.0.31903.59
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "service", "service\service.csproj", "{8572A3DF-7A4C-4552-8B30-22D794E703A6}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{8EC462FD-D22E-90A8-E5CE-7E832BA40C5D}"
|
||||
ProjectSection(SolutionItems) = preProject
|
||||
README.md = README.md
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "dbschemas", "dbschemas", "{02EA681E-C7D8-13C7-8484-4AC65E1B71E8}"
|
||||
ProjectSection(SolutionItems) = preProject
|
||||
dbschemas\01-create-posts-table.sql = dbschemas\01-create-posts-table.sql
|
||||
dbschemas\02-posts-add-updated.sql = dbschemas\02-posts-add-updated.sql
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "show-posts", "show-posts\show-posts.csproj", "{D73F984F-F3CA-4CFD-AF1A-EDE2D688294C}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Release|Any CPU = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{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}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{8572A3DF-7A4C-4552-8B30-22D794E703A6}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{D73F984F-F3CA-4CFD-AF1A-EDE2D688294C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{D73F984F-F3CA-4CFD-AF1A-EDE2D688294C}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{D73F984F-F3CA-4CFD-AF1A-EDE2D688294C}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{D73F984F-F3CA-4CFD-AF1A-EDE2D688294C}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {DD652F00-A6DC-4579-AF4C-12EA8B5C7ECC}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
|
||||
@@ -21,10 +21,9 @@ services.AddEndpointsApiExplorer();
|
||||
services.AddSwaggerGen();
|
||||
services.AddDbContext<AppDbContext>(optionsBuilder =>
|
||||
{
|
||||
// Configure the database connection string.
|
||||
var connectionString = builder.Configuration.GetValue<string>("PostgresConnection");
|
||||
Console.WriteLine($"Connecting to PostgreSQL database with connection string: {connectionString}");
|
||||
optionsBuilder.UseNpgsql(connectionString);
|
||||
var connectionString = builder.Configuration.GetValue<string>("SqliteConnection");
|
||||
Console.WriteLine($"Setting up SQLite database with {connectionString}");
|
||||
optionsBuilder.UseSqlite(connectionString);
|
||||
});
|
||||
var httpClientBuilder = services.AddHttpClient<JsonPlaceholderClient>();
|
||||
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
{
|
||||
"PostgresConnection": "Server=db;Database=mydatabase;User Id=user;Password=password;"
|
||||
}
|
||||
@@ -7,5 +7,5 @@
|
||||
}
|
||||
},
|
||||
"AllowedHosts": "*",
|
||||
"PostgresConnection": "Server=localhost;Database=mydatabase;User Id=user;Password=password;"
|
||||
}
|
||||
"SqliteConnection": "Data Source=service.db"
|
||||
}
|
||||
@@ -6,15 +6,11 @@
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="8.0.16" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="9.0.6" />
|
||||
<PackageReference Include="Microsoft.Extensions.Http.Resilience" Version="9.6.0" />
|
||||
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="9.0.4" />
|
||||
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.6.2" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="8.0.24" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="9.0.13" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="9.0.13" />
|
||||
<PackageReference Include="Microsoft.Extensions.Http.Resilience" Version="9.10.0" />
|
||||
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.9.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<Target Name="PostBuild" AfterTargets="PostBuildEvent">
|
||||
<Exec Command="docker compose up -d db" />
|
||||
</Target>
|
||||
|
||||
</Project>
|
||||
|
||||
BIN
service/service.db
Normal file
BIN
service/service.db
Normal file
Binary file not shown.
24
show-posts/Post.cs
Normal file
24
show-posts/Post.cs
Normal 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.
|
||||
}
|
||||
20
show-posts/PostsDbContext.cs
Normal file
20
show-posts/PostsDbContext.cs
Normal 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
4
show-posts/Program.cs
Normal file
@@ -0,0 +1,4 @@
|
||||
using table.lib;
|
||||
|
||||
using var context = new PostsDbContext();
|
||||
Table<Post>.Add(context.Posts.ToList()).ToConsole();
|
||||
17
show-posts/show-posts.csproj
Normal file
17
show-posts/show-posts.csproj
Normal 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>
|
||||
Reference in New Issue
Block a user