Microservices architecture got its reputation in software development since it was introduced and today, it is a very popular architectural style approach to build apps and is used by many organizations. When taking a microservices approach, you would normally break product features into services or APIs to perform specific tasks, and .NET Core is a perfect candidate to build these kinds of services.
微服务架构得到了它在软件开发中的声誉,因为据介绍,今天,这是一个非常流行的建筑风格的方法来构建应用程序,并且许多组织使用。 采用微服务方法时,通常会将产品功能分解为服务或API来执行特定任务, .NET Core是构建此类服务的理想之选。
Building APIs that can be deployed and hosted anywhere is pretty much easy nowadays when .NET Core came into life. However, if you will be building a lot of APIs to support various product features within a short timeframe, then that’s how things can get troublesome. This is because each developer/team will have their own way of building APIs and has their own standard base structure of the project. You may probably have to do a lot of copy and paste to have a consistent base structure of your API
project and configure its core dependencies all over again which can eat a lot of development time. With these reasons, ApiBoilerPlate was created.
当.NET Core出现时,构建可以在任何地方部署和托管的API变得非常容易。 但是,如果您将在短时间内构建许多API以支持各种产品功能,那么事情就会变得麻烦起来。 这是因为每个开发人员/团队都将拥有自己的API构建方式,并且拥有自己的项目标准基础结构。 您可能需要进行大量复制和粘贴操作,才能使API
项目的基础结构保持一致,并重新配置其核心依赖性,这可能会占用大量开发时间。 由于这些原因,创建了ApiBoilerPlate 。
Today, I'm happy to announce that the ApiBoilerPlate
is now officially released and can now be downloaded and installed in Visual Studio 2019 from Visual Studio Market place or via .NET CLI. I made this project open-source to allow fellow developers to contribute on it for improvements.
今天,我很高兴地宣布ApiBoilerPlate
已正式发布,现在可以从Visual Studio Market或.NET CLI下载并安装在Visual Studio 2019中。 我将此项目设为开源,以使其他开发人员可以为改进做出贡献。
ApiBoilerPlate
is a simple yet organized project template for building ASP.NET Core APIs using .NET Core 3.x (the latest/fastest version of .NET Core to date) with preconfigured tools and frameworks. The goal is to help you get up to speed when setting up the core structure of your app and its dependencies. This enables you to focus on implementing business specific requirements without you having to copy and paste the core structure of your project, and installing its dependencies all over again. This will speed up your development time when building new API project while enforcing standard project structure with its dependencies and configurations for all your apps.
ApiBoilerPlate
是一个简单而井井有条的项目模板,用于通过预配置的工具和框架使用.NET Core 3.x (迄今为止最新/最快的.NET Core版本)来构建ASP.NET Core API。 目的是帮助您快速设置应用程序的核心结构及其依赖项。 这使您可以专注于实现特定于业务的需求,而不必复制和粘贴项目的核心结构,并重新安装其依赖项。 这将在构建新的API项目时加快您的开发时间,同时通过标准项目结构及其对所有应用程序的依赖关系和配置来实施。
If you are looking for a project template for ASP.NET Core API that you can reuse across your team, or if you are new to ASP.NET Core and would like to get up to speed on how it works without having you to configure most of the basic features that an API will have, then this is for you.
如果您正在寻找一个ASP.NET Core API的项目模板,可以在整个团队中重复使用,或者您是ASP.NET Core的新手,并且想在不进行大多数配置的情况下快速了解它的工作方式API的基本功能,那么这就是给您的。
There are two ways to install the template:
有两种安装模板的方法:
From Nuget with .NET CLI: ApiBoilerPlate.AspNetCore
从具有.NET CLI的Nuget中 : ApiBoilerPlate.AspNetCore
From VSIX Market Place with Visual Studio 2019: ApiBoilerPlate.AspNetCore
从Visual Studio 2019的VSIX Market Place: ApiBoilerPlate.AspNetCore
.NET Core 3.0
.NET Core 3.0
ASP.NET Core - For building RESTful APIs
ASP.NET Core-用于构建RESTful API
Dapper - For data access.
Dapper-用于数据访问。
AutoMapper - For mapping entity models to DTOs.
AutoMapper-用于将实体模型映射到DTO。
AutoWrapper - For handling request exceptions and consistent HTTP response format.
AutoWrapper-用于处理请求异常和一致的HTTP响应格式。
Swashbuckle.AspNetCore - For API documentation
Swashbuckle.AspNetCore-用于API文档
FluentValidation.AspNetCore - For Model validations
FluentValidation.AspNetCore-用于模型验证
Serilog.AspNetCore - For logging capabilties
Serilog.AspNetCore-用于记录功能
Keep in mind that you can always replace and choose whatever framework you want to use for your API
. After all, the template is just a skeleton for your project structure with default preconfigured middlewares. For example, you can always replace Dapper
with EntityFramework Core
, PetaPoco
, etc. and configure them yourself. You can also replace Serilog
with whatever logging frameworks and providers you want that works with ASP.NET Core
- the choice is yours.
请记住,您始终可以替换并选择要用于API
任何框架。 毕竟,模板只是具有默认预配置中间件的项目结构的框架。 例如,您始终可以用EntityFramework Core
, PetaPoco
等替换Dapper
并PetaPoco
配置。 您也可以用与ASP.NET Core
Serilog
的任何日志记录框架和提供程序替换Serilog
选择由您决定。
Install the latest .NET Core SDK.
安装最新的.NET Core SDK 。
Run dotnet new -i apiboilerplate.aspnetcore
. This will install the template in your machine.
运行dotnet new -i apiboilerplate.aspnetcore
。 这会将模板安装在您的计算机中。
Run dotnet new apiboilerplate --name "MyAPI"; -o samples
. This will generate the project template named MyAPI
within the samples
directory.
运行dotnet new apiboilerplate --name "MyAPI"; -o samples
dotnet new apiboilerplate --name "MyAPI"; -o samples
。 这将在samples
目录中生成名为MyAPI
的项目模板。
Once installed, you should see this output below:
安装后,您应该在下面看到此输出:
Quote:引用:The template "ASP.NET Core API Template for .NET Core 3.x" was created successfully.
模板“ .NET Core 3.x的ASP.NET Core API模板”已成功创建。
Fire up Visual Studio 2019, click "Continue without code" link
启动Visual Studio 2019,单击“ 无代码继续 ”链接
On the "Extensions" menu, click "Manage Extensions".
在“ 扩展 ”菜单上,单击“ 管理扩展 ”。
Click "Online" and then search for "ApiBoilerPlate".
单击“ 在线 ”,然后搜索“ ApiBoilerPlate ”。
Click "Download". The extension is then scheduled for install. Close all instances of Visual Studio.
点击“ 下载 ”。 然后计划扩展安装。 关闭Visual Studio的所有实例。
The VISX (Extension) installer should popup. Click "Modify" to begin installing the template as shown in the figure below:
VISX(扩展)安装程序应弹出。 单击“ 修改 ”开始安装模板,如下图所示:
Click "Close" after modification is complete.
修改完成后,单击“ 关闭 ”。
Alternatively, you can download and install the VSIX Extension directly at the following link: https://marketplace.visualstudio.com/items?itemName=vmsdurano.ApiProjVSExt
或者,您可以直接通过以下链接下载并安装VSIX扩展: https ://marketplace.visualstudio.com/items?itemName=vmsdurano.ApiProjVSExt
Open Visual Studio 2019 and then select "Create a New Project" box
打开Visual Studio 2019,然后选择`` 创建新项目 ''框
The newly installed template should appear at the top. You can also type "ApiBoilerPlate" in the search bar:
新安装的模板应显示在顶部。 您也可以在搜索栏中输入“ ApiBoilerPlate ”:
Click the "ApiBoilerPlate" item and then click "Next".
单击“ ApiBoilerPlate ”项,然后单击“ 下一步 ”。
Name your project to whatever you like and then click "Create".
将项目命名为任意名称,然后单击“ 创建 ”。
The generated files contain the skeleton structure of the project with a very basic sample implementation for you get started working on your APIs.
生成的文件包含项目的框架结构,以及一个非常基本的示例实现,供您开始使用API。
STEP 1: Create a Test local Database:
步骤1:创建测试本地数据库:
Go to View > SQL Server Object Explorer
转到查看 > SQL Server对象资源管理器
Drilldown to SQL Server > (localdb)\MSSQLLocalDB
向下钻取到SQL Server > (localdb)\ MSSQLLocalDB
Right-click on the "Database" Folder
右键单击“ 数据库 ”文件夹
Click "Add New Database"
点击“ 添加新数据库 ”
Name it as "TestDB
" and click OK
将其命名为“ TestDB
”,然后单击“确定”。
Under "TestDB", Right-click on the "Tables" folder and select "Add New Table". Or you could simply right-click on the "TestDB" database, select "New Query" and run the script below to generate the "Person
" table.
在“ TestDB ”下,右键单击“ Tables ”文件夹,然后选择“ Add New Table ”。 或者,您可以右键单击“ TestDB ”数据库,选择“ 新建查询 ”并运行下面的脚本以生成“ Person
”表。
Name the table as "Person" with the following fields:
使用以下字段将表命名为“ Person ”:
CREATE TABLE [dbo].[Person]
(
[Id] INT NOT NULL PRIMARY KEY IDENTITY(1,1),
[FirstName] NVARCHAR(20) NOT NULL,
[LastName] NVARCHAR(20) NOT NULL,
[DateOfBirth] DATETIME NOT NULL
)
STEP 2: Update Database ConnectionString (optional)
步骤2:更新数据库ConnectionString(可选)
If you follow step 1, then you can skip this step and run the application right away.
如果执行步骤1,则可以跳过此步骤并立即运行该应用程序。
If you have a different database
and table
name then you need to change the connectionString in appsettings.json that is pointing to the newly created database. You can get the connectionString
values in the properties window of the "TestDB" database in Visual Studio.
如果您具有不同的database
和table
名,则需要在appsettings.json中更改指向新创建的数据库的connectionString 。 您可以在Visual Studio的“ TestDB ”数据库的属性窗口中获取connectionString
值。
After setting up the database, it’s time to test the API
that was preconfigured for you. Run the application and navigate to: https://localhost:44321/swagger
(See Properties > launchSettings.json to know how the application launching was configured)
设置数据库之后,是时候测试为您预先配置的API
了。 运行该应用程序并导航到: https:// localhost:44321 / swagger
(请参阅属性> launchSettings.json以了解如何配置应用程序启动)
Now, you should be presented with the Swagger UI documentation page as shown below:
现在,应该显示Swagger UI文档页面,如下所示:
Swagger provides an advance documentation for your APIs where it allows you to look the details of your API endpoints and test them when necessary. The template is preconfigured to enable this feature by default using Swashbuckle.AspNetCore tool. This means that everytime you add API
endpoints to your project, swagger will automatically generate this document without doing anything in your part. This document is very helpful as a reference especially when your APIs are publicly available and you expect many developers using it.
Swagger为您的API提供了高级文档,使您可以查看API端点的详细信息并在必要时进行测试。 默认情况下,使用Swashbuckle.AspNetCore工具将模板配置为启用此功能。 这意味着每次将API
端点添加到项目中时,swagger都会自动生成此文档,而无需您做任何事情。 该文档作为参考非常有用,特别是当您的API公开可用并且您希望许多开发人员使用它时。
Another good thing about the Swagger UI, is it allows you to test your APIs. For example, you can POST
a request to your API
and get the response back. To see that in action let’s make a POST
request with the following body parameters:
Swagger UI的另一个好处是,它允许您测试API 。 例如,您可以POST
到您请求API
,并得到响应回来。 为了看到实际效果,让我们使用以下主体参数发出POST
请求:
{
"firstName": "Vianne Maverich",
"lastName": "Durano",
"dateOfBirth": "2019-09-27T23:27:50.076Z"
}
Clicking the Execute
button gives you the following response:
单击Execute
按钮,您将获得以下响应:
Response Body:
响应主体:
{
"message": "Created Successfully",
"isError": false,
"result": 1
}
Response Header:
响应标题:
content-type: application/json
date: Fri, 27 Sep 2019 23:31:35 GMT
server: Microsoft-IIS/10.0
status: 201
x-powered-by: ASP.NET
To verify if the data was inserted to the database, you can invoke the GET
method to see the results. For this example, it should return you the following JSON payload:
要验证是否将数据插入到数据库中,可以调用GET
方法以查看结果。 对于此示例,它将返回以下JSON有效负载:
{
"message": "Request successful.",
"isError": false,
"result": [
{
"id": 1,
"firstName": "Vianne Maverich",
"lastName": "Durano",
"dateOfBirth": "2019-09-27T23:27:50.077"
}
]
}
If you notice, the HTTP
response was automatically formatted for you. The template uses AutoWrapper middleware to wrap each HTTP
responses for both success and failure without doing anything on your side. For more information, see: AutoWrapper: Prettify Your ASP.NET Core APIs with Meaningful Responses
如果您注意到, HTTP
响应将自动为您格式化。 该模板使用AutoWrapper中间件包装成功和失败的每个HTTP
响应,而无需您做任何事情。 有关更多信息,请参见: AutoWrapper:使用有意义的响应来美化您的ASP.NET Core API
Tip: Postman is also a good alternative to test APIs
and I still use that.
提示 : Postman还是测试APIs
的不错选择,我仍然使用它。
Logging is also preconfigured for you. It uses Serilog.AspNetCore
to log data. By default, the template is preconfigured to log data in Console
and File
. You can find the logs at the Logs
folder. Here’s a sample of logs that was captured based on this example:
日志也已为您预先配置。 它使用Serilog.AspNetCore
记录数据。 默认情况下,模板已预先配置为在Console
和File
记录数据。 您可以在“ Logs
文件夹中找到Logs
。 这是根据此示例捕获的日志示例:
2019-09-27T18:08:48.0418932-05:00 [INF] () Starting web host
2019-09-27T18:31:35.6179254-05:00 [INF] (AutoWrapper.AutoWrapperMiddleware) Request: POST https localhost:44321/api/v1/Persons {"firstName":"Vianne Maverich","lastName":"Durano","dateOfBirth":"2019-09-27T23:27:50.076Z"} Responded with [201] in 968ms
2019-09-27T18:34:38.6852072-05:00 [INF] (AutoWrapper.AutoWrapperMiddleware) Request: GET https localhost:44321/api/v1/Persons Responded with [200] in 87ms
To see how the log is configured, see the appsettings.logs.json
file from the project template.
要查看日志的配置方式,请参阅项目模板中的appsettings.logs.json
文件。
If you got this far, then I’m assuming you got the application up and running. At this point, you might be wondering where to start modifying the template to add your code and feel a bit confused. In this section, I’ll try my best to walk you through.
如果到此为止,那么我假设您已启动并运行该应用程序。 此时,您可能想知道从哪里开始修改模板以添加代码,并感到有些困惑。 在本节中,我将尽力帮助您。
The first thing that you may want to look at in the template is the Data
folder, which contains a class called "DBFactoryBase
". This class is an abstract class that implements a few methods to perform basic database operations:
您可能要在模板中查看的第一件事是Data
文件夹,其中包含一个名为“ DBFactoryBase
”的类。 此类是一个抽象类,它实现一些方法来执行基本的数据库操作:
namespace ApiBoilerPlate1.Data
{
public abstract class DBFactoryBase
{
private readonly IConfiguration _config;
public DBFactoryBase(IConfiguration config)
{
_config = config;
}
internal IDbConnection DbConnection
{
get {
return new SqlConnection(_config.GetConnectionString("SQLDBConnectionString"));
}
}
public virtual async Task> DbQueryAsync(string sql, object parameters = null)
{
using (IDbConnection dbCon = DbConnection)
{
dbCon.Open();
if (parameters == null)
return await dbCon.QueryAsync(sql);
return await dbCon.QueryAsync(sql, parameters);
}
}
public virtual async Task DbQuerySingleAsync(string sql, object parameters)
{
using (IDbConnection dbCon = DbConnection)
{
dbCon.Open();
return await dbCon.QueryFirstOrDefaultAsync(sql, parameters);
}
}
public virtual async Task DbExecuteAsync(string sql, object parameters)
{
using (IDbConnection dbCon = DbConnection)
{
dbCon.Open();
return await dbCon.ExecuteAsync(sql, parameters) > 0;
}
}
public virtual async Task DbExecuteScalarAsync(string sql, object parameters)
{
using (IDbConnection dbCon = DbConnection)
{
dbCon.Open();
return await dbCon.ExecuteScalarAsync(sql, parameters);
}
}
}
}
It uses Dapper
as a data access mechanism to communicate with the database. Again, you are free to modify it as you please. The main reason why I opt for Dapper
is because of its speed and simplicity. If you value convenience over performance, then you can always replace your data access with other full-blown ORM such as Entity Framework Core
.
它使用Dapper
作为与数据库通信的数据访问机制。 同样,您可以随意修改它。 我选择Dapper
的主要原因是它的速度和简单性。 如果您重视性能而不是性能,那么可以随时用其他成熟的ORM(例如Entity Framework Core
替换数据访问权限。
The next place to look at is the Contracts
folder. This is where you add all your interfaces
that are needed for your application. By default, it contains three (3) Interfaces:
下一个要查看的是Contracts
文件夹。 在这里,您可以添加应用程序所需的所有interfaces
。 默认情况下,它包含三(3)个接口:
The IRepository Interface
IRepository接口
namespace ApiBoilerPlate1.Contracts
{
public interface IRepository
{
Task> GetAllAsync();
Task GetByIdAsync(object id);
Task CreateAsync(T entity);
Task UpdateAsync(T entity);
Task DeleteAsync(object id);
Task ExistAsync(object id);
}
}
We don't want our API Controller
to access directly the DBFactoryBase
class, instead we will let other classes handle the communication between our DBFactoryBase
and API Controllers
我们不希望我们的API Controller
直接访问DBFactoryBase
类,而是让其他类处理DBFactoryBase
和API Controllers
之间的通信
The code above defines a simple generic repository interface. An interface
is just a skeleton of a method without the actual implementation.
上面的代码定义了一个简单的通用存储库接口。 interface
只是没有实际实现的方法的框架。
The IPersonManager Interface
IPersonManager界面
using ApiBoilerPlate1.Domain.Entity;
namespace ApiBoilerPlate1.Contracts
{
public interface IPersonManager : IRepository
{
//Add object specific methods here when necessary
}
}
The code above is an interface for managing the Person
entity as an example. Notice that it implements the IRepository
interface so that this interface can inherit all the available methods from the generic repository. This interface will be injected into the API Controller
so we will only need to talk to the interface rather than the actual implementation of the repository. One of the main benefits of using interface is to make our code reusable, testable, maintainable and taking advantage of Dependency Injection.
上面的代码是一个用于管理Person
实体的接口作为示例。 请注意,它实现了IRepository
接口,因此该接口可以继承通用存储库中的所有可用方法。 该接口将被注入到API Controller
因此我们只需要与该接口通信,而不是与存储库的实际实现进行对话。 使用接口的主要好处之一是使我们的代码可重用,可测试,可维护并利用依赖注入 。
The IServiceRegistration Interface
IServiceRegistration接口
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
namespace ApiBoilerPlate1.Contracts
{
public interface IServiceRegistration
{
void RegisterAppServices(IServiceCollection services, IConfiguration configuration);
}
}
The code above is an interface that will be used for services that needs to be added in IServiceCollection
.
上面的代码是一个接口,该接口将用于需要在IServiceCollection
添加的服务。
The next place to look at is the Domain
folder. This is where we implement the actual database operation and its associated logic. This folder has a sub-folder called "Entity
" wherein you define all your models for your database. Here’s the Person
entity model example:
下一个要看的地方是Domain
文件夹。 这是我们实现实际数据库操作及其关联逻辑的地方。 该文件夹有一个名为“ Entity
”的子文件夹,您可以在其中定义数据库的所有模型。 这是Person
实体模型的示例:
namespace ApiBoilerPlate1.Domain.Entity
{
public class Person
{
public long ID { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public DateTime DateOfBirth { get; set; }
}
}
The code above is nothing but a plain class that houses a few properties. The class name represents the database table name, and the properties represents the table columns.
上面的代码不过是一个普通类,其中包含一些属性。 类名表示数据库表名,属性表示表列。
The PersonManager
人事经理
namespace ApiBoilerPlate1.Domain
{
public class PersonManager : DBFactoryBase, IPersonManager
{
public PersonManager(IConfiguration config) : base(config)
{
}
public async Task> GetAllAsync()
{
return await DbQueryAsync("SELECT * FROM Person");
}
public async Task GetByIdAsync(object id)
{
return await DbQuerySingleAsync("SELECT * FROM Person WHERE ID = @ID", new { id });
}
public async Task CreateAsync(Person person)
{
string sqlQuery = $@"INSERT INTO Person (FirstName, LastName, DateOfBirth)
VALUES (@FirstName, @LastName, @DateOfBirth)
SELECT CAST(SCOPE_IDENTITY() as bigint)";
return await DbQuerySingleAsync(sqlQuery, person);
}
public async Task UpdateAsync(Person person)
{
string sqlQuery = $@"IF EXISTS (SELECT 1 FROM Person WHERE ID = @ID)
UPDATE Person SET FirstName = @FirstName, LastName = @LastName, DateOfBirth = @DateOfBirth
WHERE ID = @ID";
return await DbExecuteAsync(sqlQuery, person);
}
public async Task DeleteAsync(object id)
{
string sqlQuery = $@"IF EXISTS (SELECT 1 FROM Person WHERE ID = @ID)
DELETE Person WHERE ID = @ID";
return await DbExecuteAsync(sqlQuery, new { id });
}
public async Task ExistAsync(object id)
{
return await DbExecuteScalarAsync("SELECT COUNT(1) FROM Person WHERE ID = @ID", new { id });
}
}
}
The code above is a concrete class that implements the DBFactorBase
base class and IPersonManager
interface that we have just created earlier. This is where you implement domain specific log and database operations.
上面的代码是一个具体的类,它实现了我们之前创建的DBFactorBase
基类和IPersonManager
接口。 在这里可以实现特定于域的日志和数据库操作。
Data Transfer Object (a.k.a DTO
) are classes that defines the model with predefined validation in place. DTOs
will be passed as the parameters to your API
endpoints or use it as a return object for results. The basic idea about having a DTO
is to decouple the validation from the Entity
models and control the data that you want to allow the client to see.
数据传输对象(又名DTO
)是定义模型的类,并具有适当的预定义验证。 DTOs
将作为参数传递到您的API
端点,或将其用作结果的返回对象。 拥有DTO
的基本思想是使验证与Entity
模型脱钩,并控制要允许客户端看到的数据。
Here’s an example of the PersonDTO
:
这是PersonDTO
的示例:
using FluentValidation;
using System;
namespace ApiBoilerPlate1.DTO
{
public class PersonDTO
{
public string FirstName { get; set; }
public string LastName { get; set; }
public DateTime DateOfBirth { get; set; }
}
public class PersonDTOValidator : AbstractValidator
{
public PersonDTOValidator()
{
RuleFor(o => o.FirstName).NotEmpty();
RuleFor(o => o.LastName).NotEmpty();
RuleFor(o => o.DateOfBirth).NotEmpty();
}
}
}
The class above defines validations for the model. It uses FluentValidation.AspNetCore
to provide a clean, flexible and strongly-typed validation rules.
上面的类定义了模型的验证。 它使用FluentValidation.AspNetCore
提供干净,灵活且类型FluentValidation.AspNetCore
验证规则。
The next place to look at is the Helpers
folder. This is where you add any class that performs common tasks. For example, you can add Utility or Extension classes in this folder. By default it contains an Extensions
folder and a MapperProfile
class.
下一个要查看的地方是Helpers
文件夹。 在这里,您可以添加任何执行常规任务的类。 例如,您可以在此文件夹中添加实用程序或扩展类。 默认情况下,它包含一个Extensions
文件夹和一个MapperProfile
类。
The MappingProfile Class
MappingProfile类
using AutoMapper;
using ApiBoilerPlate1.Domain.Entity;
using ApiBoilerPlate1.DTO;
namespace ApiBoilerPlate1.Helpers
{
public class MappingProfile : Profile
{
public MappingProfile()
{
CreateMap().ReverseMap();
}
}
}
The class above is where you define the mappings between your DTOs
and Entity
models. It uses AutoMapper
to map between objects. In this example, we created a mapping between a Person
entity and a PersonDTO
model.
上面的类是定义DTOs
与Entity
模型之间的映射的地方。 它使用AutoMapper
在对象之间进行映射。 在此示例中,我们在Person
实体和PersonDTO
模型之间创建了映射。
This folder is where you add classes for your extension methods in your project. By default, it contains a ServiceRegistrationExtension
class with an extension method AddServicesInAssembly()
which is responsible for adding all available services within the assembly. This class will be called in the ConfigureServices()
method of Startup.cs file.
在此文件夹中,您可以为项目中的扩展方法添加类。 默认情况下,它包含一个ServiceRegistrationExtension
类,带有扩展方法 AddServicesInAssembly()
,该方法负责在程序 AddServicesInAssembly()
添加所有可用服务。 此类将在Startup.cs文件的ConfigureServices()
方法中调用。
Here’s the ServiceRegistrationExtension
implementation:
这是ServiceRegistrationExtension
实现:
namespace ApiBoilerPlate1.Helpers.Extensions
{
public static class ServiceRegistrationExtension
{
public static void AddServicesInAssembly(this IServiceCollection services, IConfiguration configuration)
{
var appServices = typeof(Startup).Assembly.ExportedTypes
.Where(x => typeof(IServiceRegistration)
.IsAssignableFrom(x) && !x.IsInterface && !x.IsAbstract)
.Select(Activator.CreateInstance)
.Cast().ToList();
appServices.ForEach(svc => svc.RegisterAppServices(services, configuration));
}
}
}
This is where you add services that you would want to be configured on application start up. By default, it contains two classes:
在这里,您可以添加要在应用程序启动时配置的服务。 默认情况下,它包含两个类:
The RegisterContractMappings Class
RegisterContractMappings类
namespace ApiBoilerPlate1.Installers
{
public class RegisterContractMappings : IServiceRegistration
{
public void RegisterAppServices(IServiceCollection services, IConfiguration configuration)
{
services.AddTransient();
}
}
}
The class above is responsible for registering all interface mappings between your contract repositories and concrete classes that implement the contracts.
上面的类负责注册您的合同存储库和实现合同的具体类之间的所有接口映射。
The RegisterModelValidators Class
RegisterModelValidators类
namespace ApiBoilerPlate1.Installers
{
public class RegisterModelValidators : IServiceRegistration
{
public void RegisterAppServices(IServiceCollection services, IConfiguration configuration)
{
services.AddTransient, PersonDTOValidator>();
}
}
}
The class above is responsible for registering all validators for your DTO
models. Notice that both classes above implement the IServiceRegistration
interface so that they will be configured automatically upon calling the AddServicesInAssembly()
extension method defined in ServiceRegistrationExtension
class.
上面的类负责为您的DTO
模型注册所有验证器。 请注意,以上两个类都实现了IServiceRegistration
接口,因此将在调用ServiceRegistrationExtension
类中定义的AddServicesInAssembly()
扩展方法时自动对其进行配置。
Now that we have most of the pieces in place, the next place to look at is the API
folder. This folder contains a sub-folder called "v1
" to organize Controllers
into versions. By default, the v1
folder contains the PersonsController
with the following implementation:
现在我们已经准备好了大部分内容,接下来要看的是API
文件夹。 该文件夹包含一个名为“ v1
”的子文件夹,用于将Controllers
组织成多个版本。 默认情况下, v1
文件夹包含具有以下实现的PersonsController
:
namespace ApiBoilerPlate1.API.v1
{
[Route("api/v1/[controller]")]
[ApiController]
public class PersonsController : ControllerBase
{
private readonly ILogger _logger;
private readonly IPersonManager _personManager;
private readonly IMapper _mapper;
public PersonsController(IPersonManager personManager, IMapper mapper, ILogger logger)
{
_personManager = personManager;
_mapper = mapper;
_logger = logger;
}
[HttpGet]
public async Task> Get()
{
return await _personManager.GetAllAsync();
}
[Route("{id:long}")]
[HttpGet]
public async Task Get(long id)
{
var person = await _personManager.GetByIdAsync(id);
if (person != null)
{
return person;
}
else
throw new ApiException($"Record with id: {id} does not exist.", 204);
}
[HttpPost]
public async Task Post([FromBody] PersonDTO dto)
{
if (ModelState.IsValid)
{
try
{
var person = _mapper.Map(dto);
return new ApiResponse("Created Successfully", await _personManager.CreateAsync(person), 201);
}
catch (Exception ex)
{
_logger.Log(LogLevel.Error, ex, "Error when trying to insert.");
throw;
}
}
else
throw new ApiException(ModelState.AllErrors());
}
[Route("{id:long}")]
[HttpPut]
public async Task Put(long id, [FromBody] PersonDTO dto)
{
if (ModelState.IsValid)
{
try
{
var person = _mapper.Map(dto);
person.ID = id;
if (await _personManager.UpdateAsync(person))
return new ApiResponse("Update successful.", true);
else
throw new ApiException($"Record with id: {id} does not exist.", 400);
}
catch (Exception ex)
{
_logger.Log(LogLevel.Error, ex, "Error when trying to update with ID:{@ID}", id);
throw;
}
}
else
throw new ApiException(ModelState.AllErrors());
}
[Route("{id:long}")]
[HttpDelete]
public async Task Delete(long id)
{
try
{
var isDeleted = await _personManager.DeleteAsync(id);
if (isDeleted)
{
return isDeleted;
}
else
throw new ApiException($"Record with id: {id} does not exist.", 400);
}
catch (Exception ex)
{
_logger.Log(LogLevel.Error, ex, "Error when trying to delete with ID:{@ID}", id);
throw;
}
}
}
}
The class above defines the API
endpoints and its routes with preconfigured implementation as an example. For more information about creating APIs ASP.NET Core, see: Create web APIs with ASP.NET Core
上面的类以预配置的实现为例定义了API
端点及其路由。 有关创建ASP.NET Core API的更多信息,请参见: 使用ASP.NET Core创建Web API
As an additional feature, the template includes a default example on how to run a background tasks within ASP.NET Core. Here’s the simple implementation of a worker service:
作为一项附加功能,该模板包括一个默认示例,该示例说明如何在ASP.NET Core中运行后台任务。 这是工作程序服务的简单实现:
namespace ApiBoilerPlate1.Workers
{
public class MessageQueueProcessorService : BackgroundService
{
private readonly ILogger _logger;
public MessageQueueProcessorService(ILogger logger)
{
_logger = logger;
}
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
_logger.LogDebug($"MessageQueueProcessorService is starting.");
stoppingToken.Register(() => _logger.LogDebug($" MessageQueueProcessorService background task is stopping."));
while (!stoppingToken.IsCancellationRequested)
{
_logger.LogDebug($"MessageQueueProcessorService task doing background work.");
//TO DO:
//PubSub/Message Queue subcription and process message
//Save to DB
await Task.Delay(TimeSpan.FromSeconds(5), stoppingToken);
}
_logger.LogDebug($"MessageQueueProcessorService background task is stopping.");
}
}
}
The code above simulates a simple background task that keeps on running every 5 seconds. So, if there’s a need for you to implement a worker service, then this should provides you an idea on how to get started.
上面的代码模拟了一个简单的后台任务,该任务每5秒运行一次。 因此,如果您需要实施工作人员服务,那么这应该为您提供入门的思路。
For more information about running a background tasks with hosted services in ASP.NET Core, See: Hosted Services in ASP.NET Core
有关使用ASP.NET Core中的托管服务运行后台任务的更多信息,请参见: ASP.NET Core中的托管服务
To see how each of the services in the template are configured, then take a look at the Startup.cs and Program.cs classes. To give you a quick overview, here’s how the ConfigureServices()
method of Startup.cs file looks like :
要查看如何配置模板中的每个服务,请查看Startup.cs和Program.cs类。 为了让您快速了解一下,这是Startup.cs文件的ConfigureServices()
方法的样子:
public void ConfigureServices(IServiceCollection services)
{
//Uncomment to Register Worker Service
//services.AddSingleton();
//Register DTO Validators and Interface Mappings for Repositories
services.AddServicesInAssembly(Configuration);
//Disable Automatic Model State Validation built-in to ASP.NET Core
services.Configure(opt => { opt.SuppressModelStateInvalidFilter = true; });
//Register MVC/Web API and add FluentValidation Support
services.AddControllers()
.AddFluentValidation(fv => { fv.RunDefaultMvcValidationAfterFluentValidationExecutes = false; });
//Register Automapper
services.AddAutoMapper(typeof(Helpers.MappingProfile));
//Register Swagger
services.AddSwaggerGen(c =>
{
c.SwaggerDoc("v1", new OpenApiInfo { Title = "ASP.NET Core Template API", Version = "v1" });
});
}
For more information on how the Startup
and Program
class works, read: ASP.NET Core Fundamentals
有关Startup
和Program
类如何工作的更多信息,请阅读: ASP.NET Core基础知识
In this post, we’ve learned how to use the ApiBoilerPlate
project template for building APIs in .NET Core 3.0. We've also learned about its structure and how it was implemented.
在本文中,我们学习了如何使用ApiBoilerPlate
项目模板在.NET Core 3.0中构建API。 我们还了解了它的结构及其实现方式。
I’m pretty sure there are still lots of things to improve in this project, so feel free to try it out and let me know your thoughts. Comments and suggestions are welcome, please drop a message and I’d be happy to answer any queries as I can.
我敢肯定,这个项目还有很多事情需要改进,请随时尝试一下,让我知道您的想法。 欢迎提出意见和建议,请留言,我将竭诚为您解答。
Source code can be found here: https://github.com/proudmonkey/ApiBoilerPlate
可以在这里找到源代码: https : //github.com/proudmonkey/ApiBoilerPlate
翻译自: https://www.codeproject.com/Articles/5247439/ApiBoilerPlate-A-Project-Template-for-Building-ASP