This full-stack solution allows for file uploads and downloads. The backend is a C# REST API, demonstrating how to create a clean, modern API using Clean Architecture, minimal APIs, and various design patterns. The frontend is an Angular project that demonstrates file upload and download functionality.
Example solution allows to upload/download files with .txt, .json, .csv, .xml, .yml extensions and get collection of uploaded files. Also allow to convert between json, xml, yml formats.
Two methods for downloading files are demonstrated:
- Using the GetFileAsync extension method, which returns the file as a byte array.
- Using the GetJsonFileAsync method, which returns the file inside a JSON object. The file is converted to a Base64 string to preserve encoding.
- .NET SDK 8.0+
- Angular CLI 18+
- Node.js 18.19.1+
To install the project using Git Bash:
- Clone the repository:
git clone https://github.com/Gramli/FileApi.git
- Navigate to the project directory:
cd FileApi/src
- Install the backend dependencies:
dotnet restore
- Navigate to the frontend directory and install dependencies:
cd File.Frontend npm install
- Run the solution in Visual Studio 2019+ by selecting the "Run API and FE" startup item to start both the API and the frontend servers. More about run in next section.
Expected IDE: Visual Studio 2019+
Simply select the "Run API and FE" startup item. This will start both the API and the frontend servers.
Select the "File.API" startup item and try it. Or in case You need to edit Content Type, use Postman. Example gif of how to change ContentType in Postman.
The main motivation is to create a practical example of a minimal API using Clean Architecture, while experimenting with libraries for validation and mapping, and to further improve my skills with Angular.
Projects folows Clean Architecture, but application layer is splitted to Core and Domain projects where Core project holds business rules and Domain project contains business entities.
As Minimal API allows to inject handlers into endpoint map methods, I decided to do not use MediatR, but still every endpoint has its own request and handler. Solution folows CQRS pattern, it means that handlers are separated by commands and queries, command handlers handle command requests and query handlers handle query requests. Also repositories (Repository pattern) are separated by command and queries.
Instead of throwing exceptions, project use Result pattern (using FluentResuls package) and for returning exact http response, every handler returns data wraped into HttpDataResponse object which contains also error messages collection and http response code.
Important part of every project are tests. When writing tests we want to achieve optimal code coverage. I think that every project has its own optimal code coverage number by it's need and I always follow the rule: cover your code to be able refactor without worry about functionality change.
In this solution, each 'code' project has its own unit test project and every unit test project copy the same directory structure as 'code' project, which is very helpful for orientation in test project. Infrastructure project has also integration tests, because for format conversion is used third party library and we want to know that conversion works always as expected (for example when we update library version).
The frontend is a simple Angular 18 project that demonstrates how to upload and download files as blobs or FormData from the C# API. Files are saved to the Downloads folder using the file-saver library. For styling, the project utilizes Bootstrap. Additionally, there are examples of displaying modals with ng-bootstrap and toasts/notifications with angular-notifier.