博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
简单事务:.NET Core应用程序的微服务示例体系结构
阅读量:3524 次
发布时间:2019-05-20

本文共 6506 字,大约阅读时间需要 21 分钟。

目录


介绍

这是一个.NET Core示例应用程序,以及如何构建和实现基于微服务的后端系统的示例,该系统用于简单的自动银行功能,如使用C.NETASP.NET Core Web API中的BalanceDepositWithdrawEntity FrameworkSQL Server

应用架构

示例应用程序基于微服务架构构建。使用微服务架构构建应用程序有几个优点,例如可以独立开发,部署和扩展服务。下图显示了后端架构的高级设计。

  • Identity Microservice——根据用户名,密码对用户进行身份验证,并发出JWT Bearer令牌,其中包含基于声明的身份信息
  • 交易微服务 ——处理账户交易,如获取余额,存款,取款
  • API网关 ——充当后端应用程序的中心入口点,为微服务提供数据聚合和通信路径。

微服务设计

此图显示了事务微服务(Transaction Microservice)的内部设计。与事务服务相关的业务逻辑和数据逻辑在单独的事务处理框架中编写。框架通过Web API接收输入,并根据一些简单的规则处理这些请求。事务数据存储在SQL数据库中。

安全性:基于JWT令牌的身份验证

实现基于JWT令牌的身份验证以保护WebApi服务。Identity Microservice充当Auth服务器,并在验证用户凭据后发出有效令牌。API网关将令牌发送到客户端。客户端应用程序将令牌用于后续请求。

 

开发环境

技术

  • C.NET
  • ASP.NET WEB API Core
  • SQL Server

使用的开源工具

  • Automapper (用于对象到对象的映射)
  • Entity Framework Core(用于数据访问)
  • Swashbucke(用于API文档)
  • XUnit(单元测试用例)
  • Ocelot(用于API网关聚合)

云平台服务

  • Azure App Insights(用于记录和监控)
  • Azure SQL数据库(用于数据存储)

数据库设计

WebApi终端

该应用程序在API网关中配置了四个API终端,以演示启用了基于令牌的安全选项的功能。这些路由暴露给客户端应用程序以使用后端服务。

通过API网关配置和访问终端

  1. 路由:“/user/authenticate” [HttpPost]——对用户进行身份验证并发出令牌
  2. 路由:“/account/balance” [HttpGet]——检索帐户余额
  3. 路由:“/account/deposit” [HttpPost]——存入账户金额
  4. 路由:“/account/withdraw” [HttpPost] ——从账户中提取金额

在微服务级别实现终端

  1. 路由:“/api/user/authenticate” [HttpPost]——对用户进行身份验证并发出令牌
  2. 路由:“/api/account/balance” [HttpGet]——检索帐户余额
  3. 路由:“/api/account/deposit” [HttpPost]——存入账户金额
  4. 路由:“/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

处理并发冲突的一般方法是:

  1. SaveChanges期间捕获DbUpdateConcurrencyException异常
  2. 使用DbUpdateConcurrencyException.Entries为受影响的实体准备一套新的变化
  3. 刷新并发令牌的原始值以反映数据库中的当前值
  4. 重试该过程,直到不发生冲突
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": "
" },

SwaggerAPI文档

Swashbuckle NuGet包被添加到 Transaction Microservicestartup.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集合

下载postman集合以通过网关运行API终端。

如何运行应用程序

  1. 下载SQL脚本。
  2. 针对SQL Server运行脚本以创建必要的表和示例数据。
  3. Visual Studio 2017或更高版本中打开解决方案(.sln)。
  4. Transaction.WebApi- > Appsettings.json文件中配置SQL连接string
  5. Transaction.WebApi- > Appsettings.json文件中配置AppInsights Instrumentation Key 。如果您没有密钥或不需要日志,请在Startup.cs文件中注释AppInsight相关代码。
  6. 检查Identity.WebApi- > UserService.cs文件以获取标识信息。用户详细信息是针对身份服务中可用于运行应用程序的少数帐户的硬编码。相同的细节显示在下表中。
  7. 在解决方案中运行以下项目:
    • Identity.WebApi
    • Transaction.WebApi
    • Gateway.WebApi
    • SimpleBanking.ConsoleApp
  8. 应在ConsoleApp中正确配置网关主机和端口。
  9. 应在网关 - > configuration.json正确配置标识和事务服务主机和端口。
  • 要测试的示例数据:

帐号

货币

用户名

密码

3628101

EUR

speter

test@123

3637897

EUR

gwoodhouse

pass@123

3648755

EUR

jsmith

admin@123

控制台应用——网关客户端

 

原文地址:

转载地址:http://fdzhj.baihongyu.com/

你可能感兴趣的文章
获取input选择文件的本地地址
查看>>
React绑定全局方法或变量
查看>>
js监听div标签上面的自定义属性
查看>>
navcat如何重置窗口
查看>>
代码注入
查看>>
off-by-one
查看>>
ctf-pwn的一些小技巧
查看>>
POJ 1915 Knight Moves
查看>>
Git 撤销修改
查看>>
Git 删除文件
查看>>
Git与远程仓库关联以及关联错误解决方法
查看>>
[HDU] 平方和与立方和
查看>>
[HDU 2096] 小明A+B
查看>>
[HDU 2520] 我是菜鸟,我怕谁(不一样的for循环)
查看>>
[HDU 1215] 七夕节(求因子,不超时)
查看>>
[POJ 1915] Knight Moves
查看>>
Memcache技术精华
查看>>
Redis详解入门篇
查看>>
php开启redis扩展包与redis安装
查看>>
php使用openssl来实现非对称加密
查看>>