目录
介绍
应用架构
微服务设计
安全性:基于JWT令牌的身份验证
开发环境
技术
使用的开源工具
云平台服务
数据库设计
WebApi终端
通过API网关配置和访问终端
在微服务级别实现终端
解决方案结构
异常处理
数据库并发处理
Azure AppInsights:日志记录和监控
Swagger:API文档
Postman集合
如何运行应用程序
控制台应用——网关客户端
- Download latest Repository Archive
这是一个.NET Core示例应用程序,以及如何构建和实现基于微服务的后端系统的示例,该系统用于简单的自动银行功能,如使用C#.NET的ASP.NET Core Web API中的Balance,Deposit,Withdraw,Entity Framework和SQL Server。
应用架构示例应用程序基于微服务架构构建。使用微服务架构构建应用程序有几个优点,例如可以独立开发,部署和扩展服务。下图显示了后端架构的高级设计。
- Identity Microservice——根据用户名,密码对用户进行身份验证,并发出JWT Bearer令牌,其中包含基于声明的身份信息
- 交易微服务 ——处理账户交易,如获取余额,存款,取款
- API网关 ——充当后端应用程序的中心入口点,为微服务提供数据聚合和通信路径。
此图显示了事务微服务(Transaction Microservice)的内部设计。与事务服务相关的业务逻辑和数据逻辑在单独的事务处理框架中编写。框架通过Web API接收输入,并根据一些简单的规则处理这些请求。事务数据存储在SQL数据库中。
实现基于JWT令牌的身份验证以保护WebApi服务。Identity Microservice充当Auth服务器,并在验证用户凭据后发出有效令牌。API网关将令牌发送到客户端。客户端应用程序将令牌用于后续请求。
开发环境
- .NET Core 2.2 SDK
- Visual Studio .NET 2017
- SQL Server Management Studio 17.9.1
- C#.NET
- ASP.NET WEB API Core
- SQL Server
- Automapper (用于对象到对象的映射)
- Entity Framework Core(用于数据访问)
- Swashbucke(用于API文档)
- XUnit(单元测试用例)
- Ocelot(用于API网关聚合)
- Azure App Insights(用于记录和监控)
- Azure SQL数据库(用于数据存储)
该应用程序在API网关中配置了四个API终端,以演示启用了基于令牌的安全选项的功能。这些路由暴露给客户端应用程序以使用后端服务。
通过API网关配置和访问终端- 路由:“/user/authenticate” [HttpPost]——对用户进行身份验证并发出令牌
- 路由:“/account/balance” [HttpGet]——检索帐户余额
- 路由:“/account/deposit” [HttpPost]——存入账户金额
- 路由:“/account/withdraw” [HttpPost] ——从账户中提取金额
- 路由:“/api/user/authenticate” [HttpPost]——对用户进行身份验证并发出令牌
- 路由:“/api/account/balance” [HttpGet]——检索帐户余额
- 路由:“/api/account/deposit” [HttpPost]——存入账户金额
- 路由:“/api/account/withdraw” [HttpPost]——从账户中提取金额
- Identity.WebApi
- 使用用户名,密码作为输入参数处理身份验证部分,并在其中发出带有Claims-Identity信息的JWT Bearer令牌。
- Transaction.WebApi
- 支持三种http方法,' Balance',' Deposit'和' Withdraw'。接收这些方法的http请求。
- 通过中间件处理异常
- 从包含承载令牌的授权头读取身份信息
- 在'Transaction'框架中调用适当的函数
- 将事务响应结果返回给客户端
- Transaction.Framework
- 定义存储库(数据)层和服务(业务)层的接口
- 定义领域模型(Business Objects)和实体模型(Data Model)
- 定义业务异常和领域模型验证
- 定义框架' Struct',' Enum',' Constants' 所需的数据类型
- 实现业务逻辑以执行所需的帐户事务
- 实现数据逻辑以从SQL数据库读取和更新数据
- 执行将领域模型映射到实体模型的任务,反之亦然
- 处理数据库更新并发冲突
- 通过依赖注入将接口及其实现注册到服务集合中
- Gateway.WebApi
- 通过检查其中的授权JWT令牌来验证传入的Http请求
- 将Http请求重新发送到下游服务
- SimpleBanking.ConsoleApp
- 连接到Api Gateway的控制台客户端应用程序可用于使用用户名、密码登录,并对帐户执行“ Balance',Deposit”和“ Withdraw”等交易。
编写中间件来处理异常,它在启动时注册为http请求的一部分。每个http请求都会通过此异常处理中间件,然后执行Web API控制器操作方法。
- 如果操作方法成功,则将成功响应发送回客户端。
- 如果action方法抛出任何异常,则由Middleware捕获并处理异常,并将适当的响应发送回客户端。
public async Task InvokeAsync(HttpContext context, RequestDelegate next)
{
try
{
await next(context);
}
catch (Exception ex)
{
var message = CreateMessage(context, ex);
_logger.LogError(message, ex);
await HandleExceptionAsync(context, ex);
}
}
数据库并发处理
当多个事务试图同时更新数据库中的相同数据时,数据库并发性与冲突有关。在下图中,如果您看到交易1和交易2针对同一帐户,则会尝试将金额存入帐户,而另一个系统会尝试同时从该帐户提取金额。该框架包含两个逻辑层,一个处理业务逻辑,另一个处理数据逻辑。
当从数据库中读取数据并且将业务逻辑应用于数据时,在此上下文中,与同一记录相关的值将存在三种不同的状态。
- 数据库值是当前存储在数据库中的值
- 原始值是最初从数据库中检索的值
- 当前值是应用程序尝试写入数据库的新值
当系统尝试保存更改时,每个事务中的值的状态都会产生冲突,并使用并发令牌标识更新到数据库的值不是从数据库读取的原始值并抛出DbUpdateConcurrencyException。
参考:docs.microsoft.com
处理并发冲突的一般方法是:
- 在SaveChanges期间捕获DbUpdateConcurrencyException异常
- 使用DbUpdateConcurrencyException.Entries为受影响的实体准备一套新的变化
- 刷新并发令牌的原始值以反映数据库中的当前值
- 重试该过程,直到不发生冲突
while (!isSaved)
{
try
{
await _dbContext.SaveChangesAsync();
isSaved = true;
}
catch (DbUpdateConcurrencyException ex)
{
foreach (var entry in ex.Entries)
{
if (entry.Entity is AccountSummaryEntity)
{
var databaseValues = entry.GetDatabaseValues();
if (databaseValues != null)
{
entry.OriginalValues.SetValues(databaseValues);
CalculateNewBalance();
void CalculateNewBalance()
{
var balance = (decimal)entry.OriginalValues["Balance"];
var amount = accountTransactionEntity.Amount;
if (accountTransactionEntity.TransactionType ==
TransactionType.Deposit.ToString())
{
accountSummaryEntity.Balance =
balance += amount;
}
else if (accountTransactionEntity.TransactionType ==
TransactionType.Withdrawal.ToString())
{
if(amount > balance)
throw new InsufficientBalanceException();
accountSummaryEntity.Balance =
balance -= amount;
}
}
}
else
{
throw new NotSupportedException();
}
}
}
}
}
Azure AppInsights:日志记录和监控
Azure AppInsights集成到“ Transaction Microservice ”中以收集应用程序Telemetry。
public void ConfigureServices(IServiceCollection services)
{
services.AddApplicationInsightsTelemetry(Configuration);
}
用于ASP.NET核心的AppInsights SDK提供了一个在ILoggerFactory上的扩展方法AddApplicationInsights以配置日志记录。与存款和提款相关的所有事务都会通过ILogger记录到AppInsights日志中。
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory log)
{
log.AddApplicationInsights(app.ApplicationServices, LogLevel.Information);
}
要使用AppInsights,您需要拥有Azure帐户并在Azure门户中为您的应用程序创建AppInsights实例,这将为您提供检测密钥,其在appsettings.json中进行配置。
"ApplicationInsights": {
"InstrumentationKey": ""
},
Swagger:API文档
Swashbuckle NuGet包被添加到“ Transaction Microservice”和在startup.cs中为API文档配置的swagger中间件中。运行WebApi服务时,可以通过swagger端点“/swagger” 访问swagger UI 。
public void ConfigureServices(IServiceCollection services)
{
services.AddSwaggerGen(c => {
c.SwaggerDoc("v1", new Info { Title = "Simple Transaction Processing", Version = "v1" });
});
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory log)
{
app.UseSwagger();
app.UseSwaggerUI(c => {
c.SwaggerEndpoint("/swagger/v1/swagger.json", "Simple Transaction Processing v1");
});
}
从此处下载postman集合以通过网关运行API终端。
- 从这里下载SQL脚本。
- 针对SQL Server运行脚本以创建必要的表和示例数据。
- 在Visual Studio 2017或更高版本中打开解决方案(.sln)。
- 在Transaction.WebApi- > Appsettings.json文件中配置SQL连接string
- 在Transaction.WebApi- > Appsettings.json文件中配置AppInsights Instrumentation Key 。如果您没有密钥或不需要日志,请在Startup.cs文件中注释AppInsight相关代码。
- 检查Identity.WebApi- > UserService.cs文件以获取标识信息。用户详细信息是针对身份服务中可用于运行应用程序的少数帐户的硬编码。相同的细节显示在下表中。
- 在解决方案中运行以下项目:
- Identity.WebApi
- Transaction.WebApi
- Gateway.WebApi
- SimpleBanking.ConsoleApp
- 应在ConsoleApp中正确配置网关主机和端口。
- 应在网关 - > configuration.json中正确配置标识和事务服务主机和端口。
- 要测试的示例数据:
帐号
货币
用户名
密码
3628101
EUR
speter
test@123
3637897
EUR
gwoodhouse
pass@123
3648755
EUR
jsmith
admin@123
控制台应用——网关客户端
原文地址:https://www.codeproject.com/Articles/1277140/Simple-Transaction-Microservices-Sample-Architectu