REST API avec C# et AspNet facilement que de l'écrire à partir de zéro encore et encore dans différents projets. 
REST API Controller avec CRUD complet ne contient que 20 lignes de code (~ 10 sont des importations)GET des méthodes a un support de pagination intégré ;GET des méthodes ont un tri intégré et un filtre par paramètres de requête;Create en vrac, Update et Delete ) au niveau du contrôleur et de l'interfaceIModelManager ); Bon support entité intégré (voir la classe EfModelManager ). Voir l'application WeatherControl qui possède 2 projets API Web:Wissance.WeatherControl.WebApi utilise EntityFramework ;Wissance.WeatherControl.WebApi.V2 utilise EdgeDb .Concepts clés:
Controller est une classe qui gère HTTP-requests pour REST Resource .REST Resource est égale à Entity class / Database TableREST Resource produit JSON avec DTO comme sortie. Nous supposons utiliser une seule classe DTO avec toutes les méthodes REST . Cours DTO :
OperationResultDto représente le résultat du fonctionnement qui modifie les données en DB;PagedDataDto représente la partie (page) des mêmes objets (n'importe quel type); Cours Controllers - Cours abstraits
BasicReadController ) contient 2 méthodes:GET /api/[controller]/?[page={page}&size={size}&sort={sort}&order={order}] pour obtenir PagedDataDto<T> Maintenant, nous avons également la possibilité d'envoyer n'importe quel nombre de paramètres de requête , vous devez simplement passer Filter Func à EfModelManager ou faire de votre propre manière comme dans WATherControl Exemple avec EDGedB. Nous passons également Sort (nom de colonne) && ordre ( asc ou desc ) dans les classes de gestionnaire, EfModelManager permet de trier par n'importe quelle colonne . Swagger pour afficher l'utilisation des paramètres de requête !!!1.6.0 il est possible de voir tous les paramètres de Swagger et de les utiliser.GET /api/[controller]/{id} pour obtenir un objet par idCRUD complet ( BasicCrudController ) = Contrôleur de lecture de base ( BasicReadController ) + Create , Update et Delete les opérations:POST /api/[controller] - pour la création de nouveaux objetsPUT /api/[controller]/{id} - pour modifier l'objet par idDELETE /api/[controller]/{id} - pour supprimer l'objet par idCRUD complet avec opérations en vrac (opérations sur plusieurs objets à la fois), classe de base - BasicBulkCrudController = Contrôleur de lecture de base ( BasicReadController ) + BulkCreate , BulkUpdate et BulkDelete Operations:POST /api/bulk/[controller] - pour la création d'objets de nouveaux objetsPUT /api/bulk/[controller] - pour modifier les objets passant dans un corps de demandeDELETE /api/bulk/[controller]/{idList} - pour supprimer plusieurs objets par id.Les classes de contrôleurs s'attendent à ce que toute l'opération soit effectuée à l'aide de classes Manager (chaque contrôleur doit avoir son propre gestionnaire)
Cours de gestion - Classes qui mettent en œuvre la logique commerciale de l'application
IModelManager - Interface qui décrit les opérations de baseEfModelManager - est une classe abstraite qui contient la mise en œuvre des opérations Get et DeleteEfSoftRemovableModelManager est IsDeleted = true classe abstraite qui contient la mise en œuvre des opérations Get et Delete avec des modèles amovibles en douce Exemple de la plus grande vrac vs non-Bulk: 
Elapsed time in Non-Bulk REST API with EF is 0.9759984016418457 secs.
Elapsed time in Bulk API with EF is 0.004002094268798828 secs.
En conséquence, nous avons obtenu près de ~ 250 x API plus rapide.
Il n'y a qu'une seule exigence : toutes les classes d'entités pour tout stockage de persistance qui utilisent avec les contrôleurs et les gestionnaires doivent implémenter IModelIdentifiable<T> de Wissance.WebApiToolkit.Data.Entity . Si cette boîte à outils doit être utilisée avec EntityFramework , vous devez vous dériver du gestionnaire de ressources d' EfModelManager , il a des méthodes intégrées pour:
get many articlesget one article by iddelete l'article by id L'exemple complet est mentionné dans la section 6 (voir ci-dessous). Mais si vous commencez à créer une nouvelle API REST Resource vous devez faire après:
model ( entity ) implémentant la classe IModelIdentifiable<T> et DTO pour la représentation informatique ( pour Soft Retiver Ajouter IModelSoftRemovable Implémentation), c'est-à-dire: public class BookEntity : IModelIdentifiable < int >
{
public int Id { get ; set ; }
public string Title { get ; set ; }
public string Authors { get ; set ; } // for simplicity
public DateTimeOffset Created { get ; set ; }
public DateTimeOffset Updated { get ; set ; }
}
public class BookDto
{
public int Id { get ; set ; }
public string Title { get ; set ; }
public string Authors { get ; set ; }
}Model en DTO IE: public static class BookFactory
{
public static BookDto Create ( BookEntity entity )
{
return new BookDto
{
Id = entity . Id ,
Title = entity . Title ,
Authors = entity . Authors ;
} ;
}
}IModelContext qui vous fait BookEntity en tant que DbSet et sa classe d'implémentation qui dérive également de DbContext ( EF Résumé Classe ): public interface IModelContext
{
DbSet < BookEntity > Books { get ; set ; }
}
public MoidelContext : DbContext < ModelContext > , IModelContext
{
// todo: not mrntioned here constructor, entity mapping and so on
public DbSet < BookEntity > Books { get ; set ; }
}DI DbContext injecter ModelContextController et une paire de classes Manager, c'est-à-dire considérer ici CRUD complet [ ApiController ]
public class BookController : BasicCrudController < BookDto , BookEntity , int , EmptyAdditionalFilters >
{
public BookController ( BookManager manager )
{
Manager = manager ; // this is for basic operations
_manager = manager ; // this for extended operations
}
private BookManager _manager ;
}
public class BookManager : EfModelManager < BookEntity , BookDto , int , EmptyAdditionalFilters >
{
public BookManager ( ModelContext modelContext , ILoggerFactory loggerFactory ) : base ( modelContext , BookFactory . Create , loggerFactory )
{
_modelContext = modelContext ;
}
public override async Task < OperationResultDto < StationDto > > CreateAsync ( StationDto data )
{
// todo: implement
}
public override async Task < OperationResultDto < StationDto > > UpdateAsync ( int id , StationDto data )
{
// todo: implement
}
private readonly ModelContext _modelContext ;
} Last Generic Paramètre dans l'exemple ci-dessus - EmptyAdditionalFilters est une classe qui contient des paramètres supplémentaires pour la recherche à voir dans Swagger, spécifiez simplement une nouvelle classe implémentant IReadFilterable IE:
public class BooksFilterable : IReadFilterable
{
public IDictionary < string , string > SelectFilters ( )
{
IDictionary < string , string > additionalFilters = new Dictionary < string , string > ( ) ;
if ( ! string . IsNullOrEmpty ( Title ) )
{
additionalFilters . Add ( FilterParamsNames . TitleParameter , Title ) ;
}
if ( Authors != null && Authors . Length > 0 )
{
additionalFilters . Add ( FilterParamsNames . AuthorsParameter , string . Join ( "," , Authors ) ) ;
}
return additionalFilters ;
}
[ FromQuery ( Name = "title" ) ] public string Title { get ; set ; }
[ FromQuery ( Name = "author" ) ] public string [ ] Authors { get ; set ; }
}Vous pourriez trouver Nuget-Package ici
[ ApiController ]
public class StationController : BasicCrudController < StationDto , StationEntity , int , EmptyAdditionalFilters >
{
public StationController ( StationManager manager )
{
Manager = manager ; // this is for basic operations
_manager = manager ; // this for extended operations
}
private StationManager _manager ;
} public class StationManager : EfModelManager < StationEntity , StationDto , int >
{
public StationManager ( ModelContext modelContext , ILoggerFactory loggerFactory ) : base ( modelContext , StationFactory . Create , loggerFactory )
{
_modelContext = modelContext ;
}
public override async Task < OperationResultDto < StationDto > > CreateAsync ( StationDto data )
{
try
{
StationEntity entity = StationFactory . Create ( data ) ;
await _modelContext . Stations . AddAsync ( entity ) ;
int result = await _modelContext . SaveChangesAsync ( ) ;
if ( result >= 0 )
{
return new OperationResultDto < StationDto > ( true , ( int ) HttpStatusCode . Created , null , StationFactory . Create ( entity ) ) ;
}
return new OperationResultDto < StationDto > ( false , ( int ) HttpStatusCode . InternalServerError , "An unknown error occurred during station creation" , null ) ;
}
catch ( Exception e )
{
return new OperationResultDto < StationDto > ( false , ( int ) HttpStatusCode . InternalServerError , $ "An error occurred during station creation: { e . Message } " , null ) ;
}
}
public override async Task < OperationResultDto < StationDto > > UpdateAsync ( int id , StationDto data )
{
try
{
StationEntity entity = StationFactory . Create ( data ) ;
StationEntity existingEntity = await _modelContext . Stations . FirstOrDefaultAsync ( s => s . Id == id ) ;
if ( existingEntity == null )
{
return new OperationResultDto < StationDto > ( false , ( int ) HttpStatusCode . NotFound , $ "Station with id: { id } does not exists" , null ) ;
}
// Copy only name, description and positions, create measurements if necessary from MeasurementsManager
existingEntity . Name = entity . Name ;
existingEntity . Description = existingEntity . Description ;
existingEntity . Latitude = existingEntity . Latitude ;
existingEntity . Longitude = existingEntity . Longitude ;
int result = await _modelContext . SaveChangesAsync ( ) ;
if ( result >= 0 )
{
return new OperationResultDto < StationDto > ( true , ( int ) HttpStatusCode . OK , null , StationFactory . Create ( entity ) ) ;
}
return new OperationResultDto < StationDto > ( false , ( int ) HttpStatusCode . InternalServerError , "An unknown error occurred during station update" , null ) ;
}
catch ( Exception e )
{
return new OperationResultDto < StationDto > ( false , ( int ) HttpStatusCode . InternalServerError , $ "An error occurred during station update: { e . Message } " , null ) ;
}
}
private readonly ModelContext _modelContext ;
}Juste 2 classes très simples ^^ en utilisant webapitoolkit
Considérons que nous aimerions ajouter une recherche de méthode à notre contrôleur:
[ HttpGet ]
[ Route ( "api/[controller]/search" ) ]
public async Task < PagedDataDto < BookDto > > > SearchAsync ( [ FromQuery ] string query , [ FromQuery ] int page , [ FromQuery ] int size )
{
OperationResultDto < Tuple < IList < BookDto > , long > > result = await Manager . GetAsync ( page , size , query ) ;
if ( result == null )
{
HttpContext . Response . StatusCode = ( int ) HttpStatusCode . InternalServerError ;
}
HttpContext . Response . StatusCode = result . Status ;
return new PagedDataDto < TRes > ( pageNumber , result . Data . Item2 , GetTotalPages ( result . Data . Item2 , pageSize ) , result . Data . Item1 ) ;
} Nous avons un projet supplémentaire pour protéger API avec Keycloak OpenId-Connect . Passez IHttpContextAccessor à la classe Manager et vérifiez quelque chose comme ceci: ClaimsPrincipal principal = _httpContext.HttpContext.User;
Vous pouvez voir nos articles sur l'utilisation de la boîte à outils: