WebApiToolkit
v1.6.0
C#和AspNet構建REST API 。 
CRUD的REST API Controller僅包含20行代碼(〜10是導入)GET方法具有內置的分頁支持;GET方法具有內置的排序和濾波參數過濾;Create , Update和Delete )支持批量操作&&接口級別IModelManager接口);良好的內置實體Framework支持(請參閱EfModelManager類)。請參閱具有2個Web API項目的WeatherControl應用:Wissance.WeatherControl.WebApi使用EntityFramework ;Wissance.WeatherControl.WebApi.V2使用EdgeDb 。關鍵概念:
Controller是一個將HTTP-requests為REST Resource類。REST Resource等於Entity class / Database TableREST Resource上的每個操作都以DTO為輸出產生JSON 。我們假設僅使用一個與所有REST方法一起使用一個DTO類。DTO課程:
OperationResultDto代表操作的結果,該操作會更改數據庫中的數據;PagedDataDto表示相同對象的一部分(任何類型); Controllers類 - 抽像類
BasicReadController )包含2種方法:GET /api/[controller]/?[page={page}&size={size}&sort={sort}&order={order}]現在,我們也有可能將任何數量的查詢參數發送到任何數量的查詢參數,您只需將func通過EfModelManager或以efmodelmanager或自己的方式進行審理PagedDataDto<T>或者像efmodelmmanager或自己的方式一樣。我們還將Sort(列名)&&訂單( asc或desc )傳遞給Manager類, EfModelManager允許通過任何列進行排序。Swagger Info以顯示查詢參數使用情況! ! !1.6.0開始,可以看到所有參數, Swagger使用它們。GET /api/[controller]/{id}通過id獲取一個對象CRUD Controller( Basic BasicCrudController控制器( BasicReadController ) + Create , Update和Delete操作:POST /api/[controller] - 用於新對象創建PUT /api/[controller]/{id} - 用於ID編輯對象DELETE /api/[controller]/{id} - delete對象通過IDCRUD (一次通過多個對象進行操作),基類BasicBulkCrudController =基本讀取控制器( 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 Menage模型)較快散裝與非欺凌的示例: 
Elapsed time in Non-Bulk REST API with EF is 0.9759984016418457 secs.
Elapsed time in Bulk API with EF is 0.004002094268798828 secs.
結果,我們的API速度將近250 x 。
只有一個要求:所有用於控制器和管理人員使用的持久存儲的實體類都必須從Wissance.WebApiToolkit.Data.Entity實現IModelIdentifiable<T>例使用一下。如果應與EntityFramework一起使用此工具包,則應從EfModelManager得出資源管理器,其內置方法適用於:
get many物品by id get one項目by id delete項目第6節中提到了完整示例(見下文)。但是,如果您開始構建新的REST Resource API則應執行以下操作:
model ( entity )類,以實現IT表示IModelIdentifiable<T>和DTO類(用於軟刪除還添加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 IE的出廠功能(即靜態類的靜態函數): public static class BookFactory
{
public static BookDto Create ( BookEntity entity )
{
return new BookDto
{
Id = entity . Id ,
Title = entity . Title ,
Authors = entity . Authors ;
} ;
}
}IModelContext界面,使您可以BookEntity作為DbSet及其實現類,該類也來自DbContext ( EF摘要類): 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作為DbContext通過DI參見啟動類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是一個包含其他參數以搜索的類,只需指定一個實現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 ; }
}您可以在這裡找到Nuget-ackage
[ 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;
您可以看到我們有關工具包使用的文章: