You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.09 12:50:23