这篇文章的代码和22. 【.NET 8 实战--孢子记账--从单体到微服务】--记账模块--切换主币种这篇文章的代码大体一样。这篇文章我们简单讲解一下。
既然收支记录都已经支持主币种转换的同时重新计算收支金额了,那预算也要支持切换主币种重新计算预算金额。我们一起来看一下。
一、实现
实现逻辑在这里我就不说了,不清楚的可以参考专栏的第22篇文章。
首先我们需要修改ConfigController
控制器中的Update
Action,在其中添加发布重新计算预算金额的消息,代码如下:
csharp
/// <summary>
/// 更新用户配置
/// </summary>
/// <param name="configViewModel"></param>
/// <returns></returns>
[HttpPut]
[Route("Update")]
public ActionResult<ResponseData<bool>> Update([FromBody] ConfigViewModel configViewModel)
{
try
{
//more code ....
//如果切换的是主币种,那么就将以前的所有金额全部转换成新的主币种的金额
if (configViewModel.ConfigTypeEnum == ConfigTypeEnum.Currency)
{
//more code
_ = _rabbitMqPublisher.Publish<MainCurrency>("UpdateBudgetAmount",
"UpdateBudgetAmount", new MainCurrency()
{
UserId = userId,
Currency = configViewModel.Value,
OldCurrency = oldValue
});
}
return Ok(new ResponseData<bool>(HttpStatusCode.OK, data: true));
}
catch (Exception ex)
{
return Ok(new ResponseData<bool>(HttpStatusCode.InternalServerError, "服务器异常"));
}
}
在代码中通过UpdateBudgetAmount
路由键向RabbitMQ发送重新计算预算金额的消息。接着我们修改RabbitMQBackgroundService
类中的StartAsync
方法,在其中添加处理预算金额转换的代码,代码如下:
csharp
public async System.Threading.Tasks.Task StartAsync(CancellationToken cancellationToken)
{
//more code ...
//根据新的主币种更新预算金额
await _subscriberService.SubscribeAsync<MainCurrency>("UpdateBudgetAmount", "UpdateBudgetAmount",
async (mainCurrency) =>
{
//1.获取所有预算
using var scope = _serviceProvider.CreateScope();
var budgetServer = scope.ServiceProvider.GetRequiredService<IBudgetServer>();
var budgets = budgetServer.Query(mainCurrency.UserId);
//2.将所有预算的金额转换为新的主币种(预算中的币种转换为新的主币种)
var currencyServer = scope.ServiceProvider.GetRequiredService<ICurrencyServer>();
var exchangeRateRecordServer = scope.ServiceProvider.GetRequiredService<IExchangeRateRecordServer>();
Currency? query = currencyServer.Query(mainCurrency.Currency);
if (query == null)
{
return;
}
Currency? oldCurrency = currencyServer.Query(mainCurrency.OldCurrency);
if (oldCurrency == null)
{
return;
}
//获取预算币种和主币种的汇率
ExchangeRateRecord? exchangeRateRecord =
exchangeRateRecordServer.Query($"{oldCurrency.Abbreviation}_{query.Abbreviation}");
if(exchangeRateRecord == null)
{
return;
}
for (int i = 0; i < budgets.Count; i++)
{
var budget = budgets[i];
budget.Amount = exchangeRateRecord.ExchangeRate * budget.Amount;
budget.Remaining = exchangeRateRecord.ExchangeRate * budget.Remaining;
}
//3.更新所有预算
budgetServer.Update(budgets);
});
}
新增的这段代码的功能是通过订阅RabbitMQ的消息来处理主币种变化后的预算金额更新。首先,SubscribeAsync
方法用于订阅"UpdateBudgetAmount"
消息,并为每条消息定义一个异步处理逻辑。当消息接收到后,代码会使用依赖注入容器_serviceProvider
创建一个新的服务范围scope
,以确保在处理期间可以获取所需的服务实例。接下来,代码获取IBudgetServer
服务来查询与mainCurrency.UserId
关联的所有预算。然后,它使用ICurrencyServer
和IExchangeRateRecordServer
来查询新的和旧的币种信息,以及这两种币种之间的汇率。如果查询失败,比如无法找到币种或汇率记录,处理过程将提前终止。接着,代码循环遍历所有预算,并使用获取到的汇率将每个预算的金额和剩余金额从旧币种转换为新币种。这是通过将原金额和剩余金额乘以汇率来实现的。最后,调用budgetServer.Update
方法,将更新后的预算列表保存到数据库中。
二、总结
这篇文章的代码与第22篇文章中的代码基本相同,主要目的是在主币种切换时,支持预算金额的重新计算。首先介绍了ConfigController
中的Update
方法如何在用户配置更新时,通过RabbitMQ发布"UpdateBudgetAmount"
消息,触发预算金额的重新计算。然后,文章讲解了在RabbitMQBackgroundService
中新增的代码,如何通过SubscribeAsync
方法订阅该消息并处理主币种变化后的预算更新。处理逻辑包括获取用户的所有预算、查询新旧币种及其汇率、将预算金额从旧币种转换为新币种,并最终更新预算数据。