ApiBoilerPlate:用于在.NET Core 3.x中构建ASP.NET Core API的项目模板

介绍 (Introduction)

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 。

项目模板 (The Project Template)

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的基本功能,那么这就是给您的。

如何获得? (How to get it?)

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

使用的工具和框架 (Tools and Frameworks Used)

  • .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 CorePetaPoco, 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 CorePetaPoco等替换DapperPetaPoco配置。 您也可以用与ASP.NET Core Serilog的任何日志记录框架和提供程序替换Serilog选择由您决定。

从.NET CLI安装模板 (Install the Template from .NET CLI)

  1. Install the latest .NET Core SDK.

    安装最新的.NET Core SDK 。

  2. Run dotnet new -i apiboilerplate.aspnetcore. This will install the template in your machine.

    运行dotnet new -i apiboilerplate.aspnetcore 。 这会将模板安装在您的计算机中。

  3. 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模板”已成功创建。

从Visual Studio市场安装模板 (Install the Template from the Visual Studio Marketplace)

  1. Fire up Visual Studio 2019, click "Continue without code" link

    启动Visual Studio 2019,单击“ 无代码继续 ”链接

  2. On the "Extensions" menu, click "Manage Extensions".

    在“ 扩展 ”菜单上,单击“ 管理扩展 ”。

  3. Click "Online" and then search for "ApiBoilerPlate".

    单击“ 在线 ”,然后搜索“ ApiBoilerPlate ”。

ApiBoilerPlate:用于在.NET Core 3.x中构建ASP.NET Core API的项目模板_第1张图片
  1. Click "Download". The extension is then scheduled for install. Close all instances of Visual Studio.

    点击“ 下载 ”。 然后计划扩展安装。 关闭Visual Studio的所有实例。

  2. The VISX (Extension) installer should popup. Click "Modify" to begin installing the template as shown in the figure below:

    VISX(扩展)安装程序应弹出。 单击“ 修改 ”开始安装模板,如下图所示:

ApiBoilerPlate:用于在.NET Core 3.x中构建ASP.NET Core API的项目模板_第2张图片
  1. 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

从ApiBoilerPlate模板创建一个新项目 (Create a new Project from ApiBoilerPlate Template)

  1. Open Visual Studio 2019 and then select "Create a New Project" box

    打开Visual Studio 2019,然后选择`` 创建新项目 ''框

  2. The newly installed template should appear at the top. You can also type "ApiBoilerPlate" in the search bar:

    新安装的模板应显示在顶部。 您也可以在搜索栏中输入“ ApiBoilerPlate ”:

ApiBoilerPlate:用于在.NET Core 3.x中构建ASP.NET Core API的项目模板_第3张图片
  1. Click the "ApiBoilerPlate" item and then click "Next".

    单击“ ApiBoilerPlate ”项,然后单击“ 下一步 ”。

  2. Name your project to whatever you like and then click "Create".

    将项目命名为任意名称,然后单击“ 创建 ”。

  3. Visual Studio should generate the files for you as shown in the figure below.

    Visual Studio应该为您生成文件,如下图所示。

ApiBoilerPlate:用于在.NET Core 3.x中构建ASP.NET Core API的项目模板_第4张图片

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​​。

运行模板的步骤 (Steps to run the Template)

STEP 1: Create a Test local Database:

步骤1:创建测试本地数据库:

  1. Open Visual Studio 2019

    打开Visual Studio 2019
  2. Go to View > SQL Server Object Explorer

    转到查看 > SQL Server对象资源管理器

  3. Drilldown to SQL Server > (localdb)\MSSQLLocalDB

    向下钻取到SQL Server > (localdb)\ MSSQLLocalDB

  4. Right-click on the "Database" Folder

    右键单击“ 数据库 ”文件夹

  5. Click "Add New Database"

    点击“ 添加新数据库

  6. Name it as "TestDB" and click OK

    将其命名为“ TestDB ”,然后单击“确定”。

  7. 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 ”表。

  8. 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.

如果您具有不同的databasetable名,则需要在appsettings.json中更改指向新创建的数据库的connectionString 。 您可以在Visual Studio的“ TestDB ”数据库的属性窗口中获取connectionString值。

测试默认的API控制器 (Testing the Default API Controller)

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文档页面,如下所示:

ApiBoilerPlate:用于在.NET Core 3.x中构建ASP.NET Core API的项目模板_第5张图片

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)

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记录数据。 默认情况下,模板已预先配置为在ConsoleFile记录数据。 您可以在“ 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文件。

演练 (Walkthrough)

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.

如果到此为止,那么我假设您已启动并运行该应用程序。 此时,您可能想知道从哪里开始修改模板以添加代码,并感到有些困惑。 在本节中,我将尽力帮助您。

资料夹 (Data Folder)

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替换数据访问权限。

合同文件夹 (Contracts Folder)

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类,而是让其他类处理DBFactoryBaseAPI 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添加的服务。

域文件夹 (Domain Folder)

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接口。 在这里可以实现特定于域的日志和数据库操作。

DTO文件夹 (DTO Folder)

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验证规则。

助手文件夹 (Helpers Folder)

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.

上面的类是定义DTOsEntity模型之间的映射的地方。 它使用AutoMapper在对象之间进行映射。 在此示例中,我们在Person实体和PersonDTO模型之间创建了映射。

扩展文件夹 (Extensions Folder)

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));
        }
    }
}

安装程序文件夹 (Installers Folder)

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()扩展方法时自动对其进行配置。

API文件夹 (API Folder)

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

工人文件夹 (Workers Folder)

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中的托管服务

结语 (Wrap Up)

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.csProgram.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

有关StartupProgram类如何工作的更多信息,请阅读: ASP.NET Core基础知识

摘要 (Summary)

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

你可能感兴趣的:(数据库,java,大数据,mysql,python)