REST API mit C# und AspNet einfach zu erstellen, als sie in verschiedenen Projekten immer wieder von Grund auf neu zu schreiben. 
REST API Controller mit vollem CRUD enthält nur 20 Codezeilen (~ 10 sind Importe)GET , haben ein integrierte Paging- Unterstützung.GET , haben integrierte Sortierungen und Filter durch Abfrageparameter.Create , Update und Delete ) auf einer Controller && Interface -EbeneIModelManager -Schnittstelle); Gute Unterstützung für eingebaute EntityFramework (siehe EfModelManager Klasse). Siehe Weathercontrol App mit 2 Web -API -Projekten:Wissance.WeatherControl.WebApi verwendet EntityFramework ;Wissance.WeatherControl.WebApi.V2 verwendet EdgeDb .Schlüsselkonzepte:
Controller ist eine Klasse, die HTTP-requests zur REST Resource übernimmt.REST Resource entspricht der Entity class / Database TableREST Resource erzeugt JSON mit DTO als Ausgabe. Wir gehen davon aus, dass nur eine DTO -Klasse mit allen REST verwendet wird. DTO -Klassen:
OperationResultDto stellt das Ergebnis des Betriebs dar, der die Daten in DB ändert.PagedDataDto repräsentiert Teil (Seite) derselben Objekte (jeder Typ); Controllers -Klassen - abstrakte Klassen
BasicReadController ) enthält 2 Methoden:GET /api/[controller]/?[page={page}&size={size}&sort={sort}&order={order}] EfModelManager PagedDataDto<T> zu erhalten. Jetzt haben wir auch Möglichkeiten, eine beliebige Anzahl von Abfragenparameten zu senden. Wir übergeben auch Sortier (Spaltenname) && Order ( asc oder desc ) an Manager -Klassen. EfModelManager erlaubt es, nach einer Spalte zu sortieren. Swagger -Informationen überschreiben, um Abfragungsparameter zu zeigen !!!1.6.0 ist es möglich, alle Parameter in Swagger anzuzeigen und zu verwenden.GET /api/[controller]/{id} um ein Objekt per id zu erhaltenCRUD Controller ( BasicCrudController ) = Basic Read Controller ( BasicReadController ) + Create , Update und Delete Vorgängen:POST /api/[controller] - Für die Erstellung neuer ObjektePUT /api/[controller]/{id} - für bearbeitungsobjekt durch id bearbeitenDELETE /api/[controller]/{id} - Für das Löschen von Objekt durch IDCRUD mit Bulk -Operationen (Operationen über mehrere Objekte gleichzeitig), Basisklasse - BasicBulkCrudController = Basic Lesecontroller ( BasicReadController ) + BulkCreate , BulkUpdate und BulkDelete -Operationen:POST /api/bulk/[controller] - Für die Erstellung neuer ObjektePUT /api/bulk/[controller] - Für Bearbeiten von Objekten, die in eine Anforderungsbehörde geleitet werdenDELETE /api/bulk/[controller]/{idList} - Für das Löschen mehrerer Objekte durch ID löschen.Controllers -Klassen erwarten, dass der gesamte Betrieb mit Managerklassen durchgeführt wird (jeder Controller muss seinen eigenen Manager haben).
Manager Klassen - Klassen, die die Geschäftslogik der Anwendung implementiert
IModelManager - Schnittstelle, die grundlegende Operationen beschreibtEfModelManager - ist eine abstrakte Klasse, die die Implementierung von Get & Delete von Operationen enthältEfSoftRemovableModelManager ist eine abstrakte Klasse, die die Implementierung von Get und Delete Operationen mit weichen abnehmbaren Modellen enthält ( IsDeleted = true Means -Modell wurde entfernt) Beispiel dafür, wie schneller Masse gegenüber Nicht-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.
Infolgedessen haben wir fast ~ 250 x schneller API .
Es gibt nur eine Anforderung : Alle Entitätsklassen für jede Persistenzspeicherung, die mit Controllern und Managern verwendet werden, müssen IModelIdentifiable<T> aus Wissance.WebApiToolkit.Data.Entity implementiert. Wenn dieses Toolkit mit EntityFramework verwendet werden sollte, sollten Sie Ihren Ressourcenmanager von EfModelManager abgeben. Es verfügt über integrierte Methoden für:
get many Artikelget one Artikel by idby id delete Das vollständige Beispiel wird in Abschnitt 6 erwähnt (siehe unten). Wenn Sie jedoch anfangen, eine neue REST Resource API zu erstellen, sollten Sie folgen:
model ( entity ) implementieren IModelIdentifiable<T> und DTO -Klasse für die IT -Darstellung ( für weiche Entfernen fügen auch IModelSoftRemovable -Implementierung hinzu), dh: 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 in DTO umwandelt, dh: public static class BookFactory
{
public static BookDto Create ( BookEntity entity )
{
return new BookDto
{
Id = entity . Id ,
Title = entity . Title ,
Authors = entity . Authors ;
} ;
}
}IModelContext -Schnittstelle, in der Sie als DbSet und IT IS Implementierungsklasse BookEntity , die auch von DbContext ( EF -Abstract -Klasse ) abgeleitet ist: 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 ; }
}ModelContext als DbContext über DI zu injizieren, siehe Start -up -KlasseController -Klasse und ein Managerklassenpaar, dh hier in Betracht ziehen Full CRUD [ 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 ;
} Letzter generischer Parameter im obigen Beispiel - EmptyAdditionalFilters ist eine Klasse, die zusätzliche Parameter für die Suche in Swagger enthält. Geben Sie einfach eine neue Klasse an, die IReadFilterable IE implementiert, dh:
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 ; }
}Hier finden Sie Nuget-Package
[ 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 ;
}Nur 2 sehr einfache Klassen ^^ Verwenden von WebApitoolkit
Bedenken Sie, dass wir unserem Controller Methodensuche hinzufügen möchten:
[ 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 ) ;
} Wir haben ein zusätzliches Projekt zum Schutz API mit Keycloak OpenId-Connect . Übergeben Sie IHttpContextAccessor an die Manager und überprüfen Sie so etwas: ClaimsPrincipal principal = _httpContext.HttpContext.User;
Sie konnten unsere Artikel über die Verwendung von Toolkit sehen: