在本章节,我们将着重介绍,如果搭建一个基于“.Net Core 3.1 WebAPI+EntityFrameWork+数据库”的应用程序
首先,我们需要.Net Core 3.1 WebAPI的应用程序
所需要的工具:
.Net Core 3.1运行开发环境
Visual Studio 2019
MySql 数据库或SqlServe数据库
创建空白解决方案
打开Visual Studio 2019 ->创建新项目,搜索“空白解决方案”,输入要搭建的服务名称,一般为“MYun.BPC.WebAPI.XXX”,如:
MYun.BPC.WebAPI.Basic
创建完成后,打开解决方案,选中,右键->添加->新建解决方案文件架。现阶段我们需要新增2个文件夹
01_Host 用于存放站点
02_Server 业务逻辑类库
完成后,我们就可以添加站点了
创建Action和Query站点
选中01_Host文件架,右键->添加->新建项目,搜索“ASP.NET Core Web”,选中,点击“下一步”,输入项目名称,名称一般为“MYun.BPC.WebAPI.XXX.Action”和“MYun.BPC.WebAPI.XXX.Query”如:
MYun.BPC.WebAPI.Basic.Action 用于处理端提交的操作请求
MYun.BPC.WebAPI.Basic.Query 用于处理端提交的查询请求
点击创建。这时,我们选中框架为“ASP.Net Core 3.1”,应用程序为“API”,Https配置关闭
创建完成后,效果如下:
到此,WabAPI站点创建完成,接下来,我们需要添加下面几个引用库,用来支持我们的站点
MYun.MY.Contract.Data.dll 契约类库,由类库Contract项目编译生成,用于承载返回的对象
Service.dll 框架类库,由类库Contract项目编译生成,用于承载返回对象的基类
此外,我们还需要在NuGet添加
Newtonsoft.Json
的包。用来支持Json对象的序列化
右键单击“解决方案资源管理器” -> “管理 NuGet 包”中的项目
将“包源”设置为“nuget.org”
在搜索框中输入“Newtonsoft.Json”
从“浏览”选项卡中选择“Newtonsoft.Json”包,然后单击“安装”
当前版本为“12.0.3”
为站点生成说明文档
在使用asp.net core 进行api开发完成后,书写api说明文档对于程序员来说想必是件很痛苦的事情吧,但文档又必须写,而且文档的格式如果没有具体要求的话,最终完成的文档则完全取决于开发者的心情。或者详细点,或者简单点。那么有没有一种快速有效的方法来构建api说明文档呢?答案是肯定的, Swagger就是最受欢迎的REST APIs文档生成工具之一!
为什么使用Swagger作为REST APIs文档生成工具
Swagger 可以生成一个具有互动性的API控制台,开发者可以用来快速学习和尝试API。
Swagger 可以生成客户端SDK代码用于各种不同的平台上的实现。
Swagger 文件可以在许多不同的平台上从代码注释中自动生成。
Swagger 有一个强大的社区,里面有许多强悍的贡献者。
asp.net core中如何使用Swagger生成api说明文档呢
Swashbuckle.AspNetCore 是一个开源项目,用于生成 ASP.NET Core Web API 的 Swagger 文档。
NSwag 是另一个用于将 Swagger UI 或 ReDoc 集成到 ASP.NET Core Web API 中的开源项目。 它提供了为 API 生成 C# 和 TypeScript 客户端代码的方法。
下面以Swashbuckle.AspNetCore为例为大家进行展示
右键单击选中站点 -> “管理 NuGet 包”中的项目
将“包源”设置为“nuget.org”
在搜索框中输入“Swashbuckle.AspNetCore”
从“浏览”选项卡中选择“Swashbuckle.AspNetCore”包,然后单击“安装”
当前版本为“5.6.1”
Action和Query两个站点都安装完毕后,我们再右键选中这些站点->属性->生成
XML文档文件,勾选,指定路径bin\Debug\netcoreapp3.1\MYun.BPC.WebAPI.Basic.XXX.xml
如:
bin\Debug\netcoreapp3.1\MYun.BPC.WebAPI.Basic.Query.xml
bin\Debug\netcoreapp3.1\MYun.BPC.WebAPI.Basic.Action.xml
最后,我们打开项目里的Startup.cs文件,新增引用命名空间
using Microsoft.OpenApi.Models;
using Swashbuckle.AspNetCore.Swagger;
using System.IO;
找到ConfigureServices方法。里面添加如下代码
services.AddSwaggerGen(c =>
{
c.SwaggerDoc("v1", new OpenApiInfo
{
Version = "v1", //接口文档版本
Title = "Myun .NetCore BascQuery API", //接口文档标题
Description = "基础模块BaseQuery", //描述,不同模块自己设计
});
// 为 Swagger JSON and UI设置xml文档注释路径
var basePath = Path.GetDirectoryName(typeof(Program).Assembly.Location);//获取应用程序所在目录(绝对,不受工作目录影响,建议采用此方法获取路径)
var ServicexmlPath = Path.Combine(basePath, "Service.xml"); //此为框架契约说明文档
c.IncludeXmlComments(ServicexmlPath);
var DataxmlPath = Path.Combine(basePath, "MYun.MY.Contract.Data.xml"); //此为返回对象说明文档
c.IncludeXmlComments(DataxmlPath);
var xmlPath = Path.Combine(basePath, "MYun.BPC.WebAPI.Basic.Query.xml"); //此为当前站点说明文档,Query或Action按不同站点具体配置
c.IncludeXmlComments(xmlPath);
});
找到Configure方法。里面添加如下代码
//启用中间件服务生成Swagger作为JSON终结点
app.UseSwagger();
//启用中间件服务对swagger-ui,指定Swagger JSON终结点
app.UseSwaggerUI(c =>
{
c.SwaggerEndpoint("/swagger/v1/swagger.json", "Myun .NetCore BascQuery API");
});
最终效果如下
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Microsoft.OpenApi.Models;
using Swashbuckle.AspNetCore.Swagger;
using System.IO;
namespace MYun.BPC.WebAPI.Basic.Action
{
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers();
services.AddSwaggerGen(c =>
{
c.SwaggerDoc("v1", new OpenApiInfo
{
Version = "v1", //接口文档版本
Title = "Myun .NetCore BascQuery API", //接口文档标题
Description = "基础模块BaseQuery", //描述,不同模块自己设计
});
// 为 Swagger JSON and UI设置xml文档注释路径
var basePath = Path.GetDirectoryName(typeof(Program).Assembly.Location);//获取应用程序所在目录(绝对,不受工作目录影响,建议采用此方法获取路径)
var ServicexmlPath = Path.Combine(basePath, "Service.xml"); //此为框架契约说明文档
c.IncludeXmlComments(ServicexmlPath);
var DataxmlPath = Path.Combine(basePath, "MYun.MY.Contract.Data.xml"); //此为返回对象说明文档
c.IncludeXmlComments(DataxmlPath);
var xmlPath = Path.Combine(basePath, "MYun.BPC.WebAPI.Basic.Query.xml"); //此为当前站点说明文档,Query或Action按不同站点具体配置
c.IncludeXmlComments(xmlPath);
});
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
//启用中间件服务生成Swagger作为JSON终结点
app.UseSwagger();
//启用中间件服务对swagger-ui,指定Swagger JSON终结点
app.UseSwaggerUI(c =>
{
c.SwaggerEndpoint("/swagger/v1/swagger.json", "Myun .NetCore BascQuery API");
});
}
}
}
到此,文档自动生成工具配置完成,我们现在试试效果。
我们打开项目自动生成的控制器WeatherForecastController文件和WeatherForecast文件,将各个方放加上备注说明,如下
接下来,我们右键站点->属性->调试,将“启动浏览器”修改为“swagger/index.html”
保存后,点击调试“运行”。然后打开站点http://localhost:port/swagger/index.html看下效果。发现描述字段都已经出来了
注:为了方便后期维护和节约文档撰写时间,所有.NET Core项目的公共可见类和成员,必须要有描述,如果不描述,则编译的时候会产生警告。
统一时间格式
指定当前项目时间格式统一为文本。24小时制“yyyy-MM-dd HH:mm:ss”,选中站点->添加->新增项->类,添加一个DatetimeJsonConverter类
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.Json;
using System.Text.Json.Serialization;
using System.Threading.Tasks;
namespace MYun.BPC.WebAPI.Basic.Action
{
public class DatetimeJsonConverter : JsonConverter<DateTime>
{
/// <summary>
/// 读
/// </summary>
/// <param name="reader"></param>
/// <param name="typeToConvert"></param>
/// <param name="options"></param>
/// <returns></returns>
public override DateTime Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
if (reader.TokenType == JsonTokenType.String)
{
if (DateTime.TryParse(reader.GetString(), out DateTime date))
return date;
}
return reader.GetDateTime();
}
/// <summary>
/// 写
/// </summary>
/// <param name="writer"></param>
/// <param name="value"></param>
/// <param name="options"></param>
public override void Write(Utf8JsonWriter writer, DateTime value, JsonSerializerOptions options)
{
writer.WriteStringValue(value.ToString("yyyy-MM-dd HH:mm:ss"));
}
}
}
打开Startup.cs找到ConfigureServices方法,添加一条记录
services.AddMvc().AddJsonOptions((options) =>
{
options.JsonSerializerOptions.Converters.Add(new DatetimeJsonConverter());
options.JsonSerializerOptions.Encoder = JavaScriptEncoder.Create(UnicodeRanges.All);
options.JsonSerializerOptions.PropertyNamingPolicy = null;
});
最终效果如下
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers();
services.AddMvc().AddJsonOptions((options) =>
{
options.JsonSerializerOptions.Converters.Add(new DatetimeJsonConverter());
options.JsonSerializerOptions.Encoder = JavaScriptEncoder.Create(UnicodeRanges.All);
options.JsonSerializerOptions.PropertyNamingPolicy = null;
});
services.AddSwaggerGen(c =>
{
c.SwaggerDoc("v1", new OpenApiInfo
{
Version = "v1", //接口文档版本
Title = "Myun .NetCore BascQuery API", //接口文档标题
Description = "基础模块BaseQuery", //描述,不同模块自己设计
});
// 为 Swagger JSON and UI设置xml文档注释路径
var basePath = Path.GetDirectoryName(typeof(Program).Assembly.Location);//获取应用程序所在目录(绝对,不受工作目录影响,建议采用此方法获取路径)
var ServicexmlPath = Path.Combine(basePath, "Service.xml"); //此为框架契约说明文档
c.IncludeXmlComments(ServicexmlPath);
var DataxmlPath = Path.Combine(basePath, "MYun.MY.Contract.Data.xml"); //此为返回对象说明文档
c.IncludeXmlComments(DataxmlPath);
var xmlPath = Path.Combine(basePath, "MYun.BPC.WebAPI.Basic.Action.xml"); //此为当前站点说明文档,Query或Action按不同站点具体配置
c.IncludeXmlComments(xmlPath);
});
}
这样,我们所有时间格式的输入输出,都统一为“yyyy-MM-dd HH:mm:ss”,我们用已有的WeatherForecastController控制器试试,发现时间结果都变了
指定标准接口和路由
查询请求
查询通用类库说明
QueryResponse 用来存放查询返回结果基类
QueryRequest 用来存放查询请求基类
查询路由指定”XXXQuery/[controller]/[action]”,如下:
[Route(“BasicQuery/[controller]/[action]”)]
创建一个新的查询控制器,举个例子
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
using Service;
using MYun.MY.Contract.Data.Order;
namespace MYun.BPC.WebAPI.Basic.Query.Controllers
{
[ApiController]
[Route("BasicQuery/[controller]/[action]")]
public class BasicController : ControllerBase
{
/// <summary>
/// 获取订单详情
/// </summary>
/// <param name="param"></param>
/// <returns></returns>
[HttpPost]
public QueryResponse<CPSOrder> GetOrderBySysNo(QueryRequest<CPSOrderQuerySysNo> param)
{
QueryResponse<CPSOrder> result = new QueryResponse<CPSOrder>();
#region 检测param
if (param == null)
{
result.HasError = true;
result.Fault = new MessageFault() { ErrorCode = 0, ErrorDescription = "GetLJChangeOrderBySysNo接口参数JSON对象不能为空" };
return result;
}
#endregion
try
{
#region 路由到Service
QueryResponse<CPSOrder> temp = new QueryResponse<CPSOrder>() { Body=new CPSOrder() { OrderSysNo=111, CreateTime=DateTime.Now } };
if (temp.HasError)
{
result.HasError = true;
result.Fault = temp.Fault;
}
else
{
result.Paging = temp.Paging;
result.Body = temp.Body;
}
return result;
#endregion
}
catch (Exception ex)
{
result.HasError = true;
result.Fault = new MessageFault() { ErrorCode = 0, ErrorDescription = ex.Message };
return result;
}
}
/// <summary>
/// 获取订单列表
/// </summary>
/// <param name="param"></param>
/// <returns></returns>
[HttpPost]
public QueryResponse<List<CPSOrder>> GetOrderList(QueryRequest<CPSOrderQuery> param)
{
QueryResponse<List<CPSOrder>> result = new QueryResponse<List<CPSOrder>>();
#region 检测param
if (param == null)
{
result.HasError = true;
result.Fault = new MessageFault() { ErrorCode = 0, ErrorDescription = "GetLJOrderList接口参数JSON对象不能为空" };
return result;
}
#endregion
try
{
#region 路由到Service
QueryResponse<List<CPSOrder>> temp = new QueryResponse<List<CPSOrder>>() { Body =new List<CPSOrder> { new CPSOrder() { OrderSysNo = 222, CreateTime = DateTime.Now } } };
if (temp.HasError)
{
result.HasError = true;
result.Fault = temp.Fault;
}
else
{
result.Paging = temp.Paging;
result.Body = temp.Body;
}
return result;
#endregion
}
catch (Exception ex)
{
result.HasError = true;
result.Fault = new MessageFault() { ErrorCode = 0, ErrorDescription = ex.Message };
return result;
}
}
}
}
操作请求
操作通用类库说明
ActionResponse 用来存放操作返回结果基类
ActionRequest 用来存放操作请求基类
操作路由指定”XXXAction/[controller]/[action]”,如下:
[Route(“BasicAction/[controller]/[action]”)]
创建一个新的操作控制器,举个例子
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
using Service;
using MYun.MY.Contract.Data.Order;
namespace MYun.BPC.WebAPI.Basic.Action.Controllers
{
[ApiController]
[Route("BasicAction/[controller]/[action]")]
public class BasicController : ControllerBase
{
/// <summary>
/// 新增订单
/// </summary>
/// <param name="param"></param>
/// <returns></returns>
[HttpPost]
public ActionResponse<int> AddOrderCPS(ActionRequest<OrderCPSAdd> param)
{
ActionResponse<int> result = new ActionResponse<int>();
#region 检测param
if (param == null)
{
result.HasError = true;
result.Fault = new MessageFault() { ErrorCode = 0, ErrorDescription = "AddOrderRMA接口参数JSON对象不能为空" };
return result;
}
#endregion
try
{
#region 路由到Service
return new ActionResponse<int> { Body=1 };
#endregion
}
catch (Exception ex)
{
result.HasError = true;
result.Fault = new MessageFault() { ErrorCode = 0, ErrorDescription = ex.Message };
return result;
}
}
/// <summary>
/// 编辑订单
/// </summary>
/// <param name="param"></param>
/// <returns></returns>
[HttpPost]
public ActionResponse EditOrderCPS(ActionRequest<OrderCPSEdit> param)
{
ActionResponse result = new ActionResponse();
#region 检测param
if (param == null)
{
result.HasError = true;
result.Fault = new MessageFault() { ErrorCode = 0, ErrorDescription = "EditOrderRMA接口参数JSON对象不能为空" };
return result;
}
#endregion
try
{
#region 路由到Service
return new ActionResponse();
#endregion
}
catch (Exception ex)
{
result.HasError = true;
result.Fault = new MessageFault() { ErrorCode = 0, ErrorDescription = ex.Message };
return result;
}
}
}
}
创建业务处理层
新增一个02_Server文件夹用来处理业务逻辑。然后在文件夹下,右键->新建项目
MYun.BPC.WebAPI.XXX.Server文件结构如下
Service 用于承接接口请求
ActionBP用于处理操作逻辑
QueryBP用于处理查询逻辑
Help用于存放帮助类
Transform用于存放翻译类
添加NuGet包,包内有EntityFrameworkCore等相关的引用,以及Newtonsoft.Json,EntityFrameworkCore等知识点,参考《.Net Core + EntityFramework连接数据库》
最后一步,添加相关项目程序集
然后将MYun.BPC.WebAPI.XXX.Query,MYun.BPC.WebAPI.XXX.Action这2个站点,引用MYun.BPC.WebAPI.XXX.Server这个类库