continuous-integration/drone/push Build is passing
Details
|
3 months ago | |
---|---|---|
DbContextLib | 3 months ago | |
Dtos | 3 months ago | |
Entities | 3 months ago | |
Entities2Dtos | 3 months ago | |
Shared | 3 months ago | |
Stubs | 3 months ago | |
Tests | 3 months ago | |
WebApi | 3 months ago | |
images | 3 months ago | |
.dockerignore | 3 months ago | |
.drone.yml | 3 months ago | |
.gitignore | 4 months ago | |
LICENSE | 5 months ago | |
README.md | 3 months ago | |
gazet-api.sln | 3 months ago | |
j1.md | 3 months ago |
README.md
gazet-api
Nous avons déplacé la partie du J1 dans le fichier j1.md
Built with
- Language: C# 12
- ORM: Entity Framework Core 8
- API: ASP.NET Core 8
- Unit testing: xUnit
- Database: PostgresSQL, SQLite (not recommended for production)
MLD
classDiagram
user <|-- source
user <|-- tag
user <|-- collection
collection <|-- belongs_to
tag <|-- has_tag
content <|-- belongs_to
content <|-- has_tag
content_type <|-- content
class belongs_to {
long CollectionId
long ContentId
date CreatedAt
bool IsFavorite
bool IsVisible
}
class collection {
long Id
long TeacherId
string name
date CreatedAt
}
class content {
long Id
string title
string content_type
string? url
string source
string? comment
}
class content_type {
long Id
string type
}
class has_tag {
long Id
long ContentId
}
class tag {
long Id
long TeacherId
string name
}
class user {
long Id
string Username
string Email
string Password
date CreatedAt
string Role
}
class source {
long Id
long UserId
string name
string url
}
How to tun migrations
cd StubbedContextLib
dotnet ef migrations add MigrationName
dotnet ef database update MigrationName
How to run the tests
dotnet test
How to run console tests for WebApi
It’s possible when you run consoles tests for WebApi that you have an error of port and authorization. It’s certainly due to the base address of the client in the firsts lines. Just change the port after localhost in the string to correspond to the correct port where WebApi is launched. Also change if you use http or https at the beginning of the address.
Project structure
All tests (Unit and Console) are located in the Tests
folder under the name of the project followed by .UnitTests
or .ConsoleTests
.
We have 2 main parts in the project:
- WebApi: a RESTful API using ASP.NET 8
- DbContext: an Entity Framework Core 8 context AS ORM
The other projects are serve the 2 mentioned before and are used to separate concerns and make the code more maintainable.
Data
The way we transfer data between the API and the client are through DTOs
which are located in the DTO
project.
The way we store data in the database and the ORM is working with is through Entity
which are located in the Entity
project.
Then to make the link between the DTO
and the Entity
, we are using extensions (ToDto
/ToDtos
and ToEntity/ToEntities
) methods to transform Entity
to DTO
and vice versa.
Handling the data
We have multiple interfaces that represent what we can do with the data. For example, we have IUserManager
that represents the operations we can do with the User
entity and DTO.
Our interface is generic, meaning we can use the same interface for Entities and DTOs. This is useful to avoid code duplication and to make sure that the same operations are available for both entities and DTOs.
We implement these interfaces in their respective project as mentioned below.
On the ORM side
We have Type
DbManagers that implement the interfaces mentioned above to manipulate entities across the ORM, this usually include CRUD operations and more specific methods such GetByName
. These are located in the DbManagers
folders in the DbContext project.
On the API side
We also have Type
DtoManagers that implement the interfaces mentioned above to be called from the controllers to call the DbManager in the ORM to perform the actual operation. At this point we estimate that the controllers have done their work to check if the given data are valid and won't be checked later. Those are located in the Managers
folders in the WebApi project.
Sample data et utilisation
Pagination : Order By, Page, PageSize peuvent être laissés vide et prendront par défaut les 25 premiers éléments non triés. PageSize ne peut quant à lui pas dépasser 50.
Voici quelques champs préremplit pour tester les tags : Pour récupérer/delete/update par id : id de 1 à 9 disponibles par nom : vela ou course sont disponibles
Name : littérature, Réseaux UserId : users de 1 à 4 disponibles
Conception
La partie Entity Framework (ORM) contient les projets suivants
- Entities
- DbContextLib
- StubbedContext
- DbContextLib.ConsoleTests
- DbContextLib.UnitTests
La partie ASP.NET (API) contient les projets suivants
- Dtos
- WebApi
- StubbedStoLib
- WebApi.ConsoleTests
- WebApi.UnitTests
Le projet Shared
contient les ressources partagées entre la partie EF et API
Le projet Entities2Dtos
est responsable de la transformation d'entités vers leur DTO associés et inversement
Diagrammes de classes
EF
Voici les diagrammes de classes, respectivement de la partie EF puis API. Nous avons volontairement omis certaines classes redondantes par soucis de lisibilité, la compréhension ne devrait pas être altérée
classDiagram
Entity <|-- UserEntity
Entity <|-- CollectionEntity
Entity <|-- ContentEntity
DBManager <|-- IDbManager
CollectionEntity "" <-- UserEntity
ContentEntity "" <-- CollectionEntity
UnitOfWork <-- DBManager
GazetDbContext <-- DBManager
ContentEntity "" <-- GazetDbContext
CollectionEntity "" <-- GazetDbContext
UserEntity "*" <-- GazetDbContext
GenericRepository "Un par entité" <-- UnitOfWork
class Entity{
}
class ContentEntity{
+long Id
+long? ContentTypeId
+ContentTypeEntity ContentType
+long? SourceId
+SourceEntity Source
+string Title
+string? Url
+string? Comment
+DateTime PublishedAt
}
class UserEntity{
+long Id
+string Username
+string Email
+string Password
+DateTime CreatedAt
+Role Role
}
class CollectionEntity{
+long Id
+string Name
+long UserId
+UserEntity User
+DateTime CreatedAt
}
class GenericRepository{
+Create()
+Delete()
+Update()
+GetById()
+Get()
}
class UnitOfWork{
}
class DBManager{
}
class GazetDbContext{
}
class IDbManager {
<<Interface>>
}
API
classDiagram
IDbManager <|-- DtoManager
DtoManager <-- Controller
ContentDto <.. DtoManager
CollectionDto <.. DtoManager
UserDto <.. DtoManager
Program <-- Controller
class IDbManager {
<<Interface>>
}
class DtoManager {
+Get()
+Getby...()
...()
}
class Controller{
+Get()
+Getby...()
...()
}
class ContentDto{
+long Id
+string Title
+string Url
+string? Comment
+DateTime PublishedAt
}
class CollectionDto{
+long Id
+long UserId
+string Name
+DateTime CreatedAt
}
class UserDto{
+long Id
+string Username
+string Email
+string Password
+DateTime CreatedAt
+Role Role
}
class Program{
}
Évolution par rapport au J1
Pour le J2, nous avons donc déployé l'api sur CodeFirst à l'adresse suivante : https://codefirst.iut.uca.fr/containers/simonguillot2-gazet-api-container
De plus, nous avons implémenté les Controllers, Dto manager et EntityManager qu'il nous manquait. À savoir pour les éléments suivants : collection, content et source. De plus, nous avons mis le patron Unit Of Work afin de factoriser certaines actions. Enfin, nous avons fait une grande partie des tests pour s'assurer du bon fonctionnement de l'API.
Extra J2 (couverture de tests, tests de charge et de performances)
Pour la partie extra en J2, par manque de temps et le fait que nous avions déjà commencé à le faire pour une autre SAE, nous avons décidé d'augmenter la couverture de tests ainsi que d'effectuer des tests de charge et de performances.
Couverture de tests
Selon Sonar, nous avons 75% de code coverage avec ce que l'on estime être de "bons" tests et côté IDE, il nous indique 84% avec la répartition suivante
Tests de charge
Pour mesurer et monitorer l’utilisation de la mémoire, nous avons utilisé dotMemory, un outil de profiling de JetBrains. Pour cela, nous avons d’abord compilé le projet en mode Release, puis configuré le profiler pour lancer l’exécutable généré et analyser celui-ci. Voici les résultats pour 100 requêtes par seconde.
i5-3570k (GNU/Linux)
Mac
Comme on peut le constater sur les deux graphiques ci-dessus, on constate que se fait en dents de scie, montrant bien les allocations de mémoire nécessaire à toutes nos requêtes, puis l’appel du garbage collector qui supprime les objets plus utilisés.
Tests de performance
Dans un second temps, nous avons voulu nous assurer que notre API était performante afin que le temps de réponse pour nos clients soient les meilleurs possibles, pour ça nous avons utilisé l’outil de mesure de performance de Postman. Voici les résultats
i5-3570k (GNU/Linux)
Mac
Dans les deux cas, on peut constater que les performances sont excellentes et très stables. Ainsi, nous pouvons consommer notre API sans craindre d’impacts de performance même avec un trafic 5 fois plus élevé que la capacité maximum prévue.
Piste d'amélioration si nous avions eu plus de temps
Si nous avions eu plus de temps, nous aurions
- Utiliser nos UserEntity comme IdentityUser et réécrire le controller d'authentification
- Injecter un fournisseur de base de données côté API