如何在ASP.NET Core中用ExchangeRate-API实现薪资货币转换?
ASP.NET Core 中基于 ExchangeRate-API 实现货币转换的正确方案
需求:用户输入外币薪资和对应币种,自动转换为 EUR 和 USD 金额并保存。
现有代码核心问题
EmployeeCategory模型缺少外币币种字段,无法确定转换基准NetSalary_EUR被标记为[Required],但该字段是转换结果,不应由用户输入ExchangeRate_API类仅获取汇率但未返回可用转换数据,也未处理指定币种的转换逻辑- 使用已过时的
WebClient,ASP.NET Core 中推荐使用HttpClient - Create 接口未调用转换逻辑,直接保存用户输入的 EUR/USD 值,不符合自动转换需求
1. 修正实体模型
更新EmployeeCategory,添加币种字段并调整必填项:
using System.ComponentModel.DataAnnotations; namespace Test_Project_Web.Models { public class EmployeeCategory { [Key] public int Id { get; set; } [Required(ErrorMessage = "请输入外币薪资")] [Range(0.01, double.MaxValue, ErrorMessage = "薪资必须大于0")] public double GrossSalary_ForeignCurrency { get; set; } [Required(ErrorMessage = "请选择外币币种")] [StringLength(3, MinimumLength = 3, ErrorMessage = "币种代码必须为3位(如USD、GBP)")] public string ForeignCurrencyCode { get; set; } = string.Empty; // 转换结果,无需用户输入,移除[Required] public double NetSalary_EUR { get; set; } public double NetSalary_USD { get; set; } } }
2. 重构汇率服务
创建专门的汇率服务类,使用HttpClient调用 API 并封装转换逻辑:
using Newtonsoft.Json; namespace Test_Project_Web.Services { public interface IExchangeRateService { // 获取指定币种到EUR和USD的转换汇率 Task<(double EurRate, double UsdRate)?> GetConversionRatesAsync(string baseCurrency); // 计算转换后的金额 (double EurAmount, double UsdAmount) ConvertSalary(double foreignSalary, double eurRate, double usdRate); } public class ExchangeRateService : IExchangeRateService { private readonly HttpClient _httpClient; private const string ApiKey = "YOUR-API-KEY"; // 替换为你的API密钥 private const string ApiBaseUrl = "https://v6.exchangerate-api.com/v6/{0}/latest/{1}"; public ExchangeRateService(HttpClient httpClient) { _httpClient = httpClient; } public async Task<(double EurRate, double UsdRate)?> GetConversionRatesAsync(string baseCurrency) { try { var url = string.Format(ApiBaseUrl, ApiKey, baseCurrency.ToUpper()); var response = await _httpClient.GetAsync(url); response.EnsureSuccessStatusCode(); var json = await response.Content.ReadAsStringAsync(); var apiResponse = JsonConvert.DeserializeObject<ExchangeRateApiResponse>(json); if (apiResponse?.Result != "success" || apiResponse.ConversionRates == null) return null; if (apiResponse.ConversionRates.TryGetValue("EUR", out var eurRate) && apiResponse.ConversionRates.TryGetValue("USD", out var usdRate)) { return (eurRate, usdRate); } return null; } catch { return null; } } public (double EurAmount, double UsdAmount) ConvertSalary(double foreignSalary, double eurRate, double usdRate) { var eurAmount = foreignSalary * eurRate; var usdAmount = foreignSalary * usdRate; return (Math.Round(eurAmount, 2), Math.Round(usdAmount, 2)); } } // API响应模型,匹配返回结构 internal class ExchangeRateApiResponse { [JsonProperty("result")] public string? Result { get; set; } [JsonProperty("conversion_rates")] public Dictionary<string, double>? ConversionRates { get; set; } } }
3. 注册服务并更新Controller
在Program.cs中注册服务:
builder.Services.AddHttpClient<IExchangeRateService, ExchangeRateService>();
更新EmployeeCategoryController,注入服务并执行转换逻辑:
using Microsoft.AspNetCore.Mvc; using Test_Project_Web.Data; using Test_Project_Web.Models; using Test_Project_Web.Services; namespace Test_Project_Web.Controllers { public class EmployeeCategoryController : Controller { private readonly ApplicationDbContext _db; private readonly IExchangeRateService _exchangeRateService; public EmployeeCategoryController(ApplicationDbContext db, IExchangeRateService exchangeRateService) { _db = db; _exchangeRateService = exchangeRateService; } public IActionResult Index() { var objEmployeeCategoryList = _db.EmployeeCategories.ToList(); return View(objEmployeeCategoryList); } public IActionResult Create() { return View(); } [HttpPost] [AutoValidateAntiforgeryToken] public async Task<IActionResult> Create(EmployeeCategory obj) { if (!ModelState.IsValid) return View(obj); var rates = await _exchangeRateService.GetConversionRatesAsync(obj.ForeignCurrencyCode); if (rates == null) { ModelState.AddModelError(string.Empty, "获取汇率失败,请检查币种代码或稍后重试"); return View(obj); } var convertedSalaries = _exchangeRateService.ConvertSalary(obj.GrossSalary_ForeignCurrency, rates.Value.EurRate, rates.Value.UsdRate); obj.NetSalary_EUR = convertedSalaries.EurAmount; obj.NetSalary_USD = convertedSalaries.UsdAmount; _db.EmployeeCategories.Add(obj); await _db.SaveChangesAsync(); return RedirectToAction("Index"); } } }
4. 修正Create视图(Create.cshtml)
仅让用户输入外币薪资和币种,转换结果设为只读:
@model Test_Project_Web.Models.EmployeeCategory @{ ViewData["Title"] = "Create"; } <h1>Create Employee Salary</h1> <hr /> <div class="row"> <div class="col-md-4"> <form asp-action="Create"> <div asp-validation-summary="ModelOnly" class="text-danger"></div> <div class="form-group"> <label asp-for="GrossSalary_ForeignCurrency" class="control-label"></label> <input asp-for="GrossSalary_ForeignCurrency" class="form-control" /> <span asp-validation-for="GrossSalary_ForeignCurrency" class="text-danger"></span> </div> <div class="form-group"> <label asp-for="ForeignCurrencyCode" class="control-label"></label> <input asp-for="ForeignCurrencyCode" class="form-control" placeholder="如GBP、JPY" /> <span asp-validation-for="ForeignCurrencyCode" class="text-danger"></span> </div> <div class="form-group mt-3"> <label class="control-label">转换结果(EUR)</label> <input type="text" class="form-control" value="@Model.NetSalary_EUR" readonly /> </div> <div class="form-group mt-3"> <label class="control-label">转换结果(USD)</label> <input type="text" class="form-control" value="@Model.NetSalary_USD" readonly /> </div> <div class="form-group mt-4"> <input type="submit" value="Create" class="btn btn-primary" /> </div> </form> </div> </div> <div> <a asp-action="Index">Back to List</a> </div> @section Scripts { @{await Html.RenderPartialAsync("_ValidationScriptsPartial");} }
内容的提问来源于stack exchange,提问作者Unity_cube
相关产品推荐
相关产品推荐

