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#
|
* .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:00 AM +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
|
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -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
|
|
||||||
@@ -7,8 +7,6 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "service", "service\service.
|
|||||||
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
|
|
||||||
Dockerfile = Dockerfile
|
|
||||||
README.md = README.md
|
README.md = README.md
|
||||||
EndProjectSection
|
EndProjectSection
|
||||||
EndProject
|
EndProject
|
||||||
@@ -18,6 +16,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "dbschemas", "dbschemas", "{
|
|||||||
dbschemas\02-posts-add-updated.sql = dbschemas\02-posts-add-updated.sql
|
dbschemas\02-posts-add-updated.sql = dbschemas\02-posts-add-updated.sql
|
||||||
EndProjectSection
|
EndProjectSection
|
||||||
EndProject
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "show-posts", "show-posts\show-posts.csproj", "{D73F984F-F3CA-4CFD-AF1A-EDE2D688294C}"
|
||||||
|
EndProject
|
||||||
Global
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
Debug|Any CPU = Debug|Any CPU
|
Debug|Any CPU = Debug|Any CPU
|
||||||
@@ -28,6 +28,10 @@ Global
|
|||||||
{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
|
||||||
|
{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
|
EndGlobalSection
|
||||||
GlobalSection(SolutionProperties) = preSolution
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
HideSolutionNode = FALSE
|
HideSolutionNode = FALSE
|
||||||
|
|||||||
@@ -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>();
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +0,0 @@
|
|||||||
{
|
|
||||||
"PostgresConnection": "Server=db;Database=mydatabase;User Id=user;Password=password;"
|
|
||||||
}
|
|
||||||
@@ -7,5 +7,5 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"AllowedHosts": "*",
|
"AllowedHosts": "*",
|
||||||
"PostgresConnection": "Server=localhost;Database=mydatabase;User Id=user;Password=password;"
|
"SqliteConnection": "Data Source=service.db"
|
||||||
}
|
}
|
||||||
@@ -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
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