C#とAspNetを使用してREST APIを簡単に作成するのに役立ちます。 
CRUDを備えたREST API Controllerには、20行のコードのみが含まれています(〜10はインポートです)GETにはページングサポートが組み込まれています。GETメソッドには、クエリパラメーターごとに組み込みのソートとフィルターが組み込まれています。Create 、 Update 、 Delete )を使用してバルク操作をサポートしますIModelManagerインターフェイス)で動作することをサポートします。優れた組み込みEntityFrameworkサポート( EfModelManagerクラスを参照)。 2つのWeb APIプロジェクトを備えたWeatherControlアプリを参照してください。Wissance.WeatherControl.WebApi 、 EntityFrameworkを使用します。Wissance.WeatherControl.WebApi.V2はEdgeDbを使用します。重要な概念:
ControllerはHTTP-requestsを処理してREST Resourceクラスです。REST ResourceはEntity class / Database Tableに等しいREST Resource上のすべての操作は、 DTOを出力としてJSONを生成します。すべてのRESTメソッドを備えた1つのDTOクラスのみを使用すると想定しています。DTOクラス:
OperationResultDto 、DBのデータを変更する操作の結果を表します。PagedDataDto 、同じオブジェクト(任意のタイプ)の部分(ページ)を表します。 Controllersクラス - 抽象クラス
BasicReadController )には2つの方法が含まれています。GET /api/[controller]/?[page={page}&size={size}&sort={sort}&order={order}] PagedDataDto<T>するには、クエリパラEfModelManagerを数多く送信する可能性もあります。また、sort(列名)&& order( ascまたはdesc )をマネージャークラスに渡すと、 EfModelManager任意の列でソートできます。Swagger情報をオーバーライドする必要があります!!!1.6.0から、すべてのパラメーターをSwaggerで表示して使用することができます。GET /api/[controller]/{id}て、 idで1つのオブジェクトを取得しますCRUD Controller( BasicCrudController )= Basic Read Controller( BasicReadController ) +操作Create 、 Update 、 Delete :POST /api/[controller] - 新しいオブジェクト作成用PUT /api/[controller]/{id} - IDでオブジェクトを編集しますDELETE /api/[controller]/{id} - idによってオブジェクトを削除しますCRUD (複数のオブジェクトを一度に操作)、ベースクラスBasicBulkCrudController = Basic Read Controller( BasicReadController ) + BulkCreate 、 BulkUpdate 、およびBulkDelete操作:POST /api/bulk/[controller] - 新しいオブジェクトの作成用PUT /api/bulk/[controller] - リクエストボディを渡すオブジェクトを編集するためDELETE /api/bulk/[controller]/{idList} - IDで複数のオブジェクトを削除します。コントローラークラスは、すべての操作がマネージャークラスを使用して実行されることを期待しています(各コントローラーは自分のマネージャーを持っている必要があります)
マネージャークラス - アプリケーションのビジネスロジックを実装するクラス
IModelManager基本操作を説明するインターフェイスEfModelManager GetおよびDelete操作の実装を含む抽象クラスですEfSoftRemovableModelManager 、ソフト取り外し可能なモデルを使用したGetおよびDelete操作の実装を含む抽象クラスです( IsDeleted = true Meansモデルが削除されました)バルクと非バルクの速さの例: 
Elapsed time in Non-Bulk REST API with EF is 0.9759984016418457 secs.
Elapsed time in Bulk API with EF is 0.004002094268798828 secs.
その結果、ほぼ250 xより速いAPIを獲得しました。
要件は1つだけです。コントローラーとマネージャーで使用している永続性ストレージのすべてのエンティティクラスは、 Wissance.WebApiToolkit.Data.EntityからIModelIdentifiable<T>を実装する必要があります。このツールキットをEntityFrameworkで使用する場合は、 EfModelManagerからリソースマネージャーを導き出す必要があります。
get manyby id get oneby idアイテムdelete完全な例については、セクション6に記載されています(以下を参照)。ただし、新しいREST Resource API構築を開始している場合は、次のようにする必要があります。
IModelIdentifiable<T>およびDTOクラスを実装するmodel ( entity )クラスを作成します(ソフト削除の場合もIModelSoftRemovable実装を追加します)、つまり: 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をDTOに変換する工場関数(つまり、静的クラスの静的関数)を作成します。 public static class BookFactory
{
public static BookDto Create ( BookEntity entity )
{
return new BookDto
{
Id = entity . Id ,
Title = entity . Title ,
Authors = entity . Authors ;
} ;
}
}DbSetとしてBookEntity獲得したIModelContextインターフェイスを作成し、 DbContext ( EF Abstract Class )からも派生する実装クラスです。 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としてModelContextを挿入するように構成スタートアップクラスを参照してくださいControllerクラスとマネージャークラスの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 ;
}上記の例の最後の汎用パラメーター - EmptyAdditionalFiltersは、検索がSwaggerで表示される追加のパラメーターを保持するクラスで、 IReadFilterable実装する新しいクラスを指定するだけです。
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 ; }
}ここでナゲットパッケージを見つけることができます
[ 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 ;
}わずか2つの非常にシンプルなクラス^^ webapitoolkitを使用しています
コントローラーにメソッド検索を追加したいと考えてください。
[ 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 ) ;
} Keycloak OpenId-Connectを使用してAPIを保護するための追加のプロジェクトがあります。 IHttpContextAccessorをManagerクラスに渡し、次のようなものを確認しますClaimsPrincipal principal = _httpContext.HttpContext.User;
ツールキットの使用に関する記事を見ることができます。