FileSystemAPI is an attempt to create a fully RESTful API for browser based file system services. It is powered by .NET 8 and EF Core 8 and it supports basic operations on files and directories:
- Read
- Write
- Update
- Move
- Delete
There are 5 launch profiles available:
- FileSystem standard launch profile
- FileSystem_WithGeneratedData profile that runs the parallel Task which generates and saves random data
- Number of randomly generated content can be configured by editing the launch profile's command line args ([minCustomerCount] [maxCustomerCount] [minContentCount] [maxContentCount])
"commandLineArgs": "100 150 100 1000"- the above example ensures there will be 100-150 customers and 100-1000 content items for each one of them (so, worst case, this will generate 150 * 1000 content items)
- Number of randomly generated content can be configured by editing the launch profile's command line args ([minCustomerCount] [maxCustomerCount] [minContentCount] [maxContentCount])
- Docker Compose (docker-compose project)
- Update the connection
- Docker profile
- WSL profile
- Open up an IDE of your liking (Visual Studio >= 2022, VS Code or Rider with all the packages needed for building and running the app)
- Run the app (FileSystem launch profile is selected by default)
- Switch to docker-compose project
- Switch to docker db connection string in appsettings.Development.json
- Ensure Docker Desktop is installed
- Create and run SQL server container instance
- Switch to docker db connection string in appsettings.Development.json
- Ensure you have WSL version 2 enabled and Ubuntu 20.04 distro installed
- Start the distro and
- Install .NET 8 runtime
- Install VSDebugger tool
- Install docker
- Create and run SQL server container instance
- Switch to docker db connection string in appsettings.Development.json
Directories and files are treated as a content and, as such, stored in the same database table. But, to be able to differentiate between them, following rules are applied:
- Type value is different (0 = directory / 1 = file)
- The relative Path contains the extension if it is related to a file
- Directories can have descendants, files cannot
And to "isolate" user's file system, each item has a reference to the CustomerId. This value is also a required component of each HTTP request as a prefix in resource URL's, e.g.:
https://[Domain]/[CustomerId]/...
As mentioned, there is only one table that stores both directories and files.
| Id | CustomerId | Name | Path | Type | ParentId | Created | Modified | RowVersion |
|---|---|---|---|---|---|---|---|---|
| GUID | GUID | NVARCHAR(255) | NVARCHAR(450) | TINYINT | GUID | BIGINT | BIGINT | ROWVERSION |
- Id content identifier
- CustomerId customer identifier
- Name content name (without the extension if it's a file)
- Path path relative to the user's root directory (with an extension if it's a file)
- ParentId content identifier which is an ancestor of the current item
- Created UNIX timestamp at which the content was created
- Modified UNIX timestamp pat which the content was last modified
- RowVersion unique binary value used in concurrency handling
Idea is not to store file content in the database (database file) because that doesn't seem as a viable solution for large scale file system services (tbh, it depends on the database - for example, SQL server stores the data in a separate disk location). Anyway, file content should be physically stored somewhere else, preferably not in the same location where the database is found. To enable this, a file system interaction needs to be added.
Directory structure is exactly what you would expect, classic top-down hierarchy with a root directory:
└── c145b03e-2597-4ad6-8a2f-d331905658ef
└── Directory_1
├── Directory_1_1
├── File_1_1.txt
└── Directory_2
└── dbd9168b-da2a-4390-8113-e7096baa78a6
└── Directory_1
└── Directory_2
└── Directory_2_1