C#中如何实现合并两个REST端点结果的第三方端点?
最优实现方案
首先,不建议先调用端点A再用返回的ID调用端点B——如果用户传入的是城市名称(无ID),串行调用会增加请求延迟;如果是ID列表,重复调用B也会浪费资源。更优的方式是:
- 直接使用当前端点接收到的请求参数(城市名/城市名+ID列表),并行调用端点A和端点B,同时获取两组数据
- 以公司ID为唯一标识,将两组数据进行合并
这种方式能减少总请求耗时(并行比串行更快),逻辑清晰,也能完整保留端点A的原始数据。
具体实现步骤(C#)
假设你基于ASP.NET Core开发:
1. 定义强类型数据模型(推荐)
为三个端点的返回数据定义DTO(数据传输对象),保证类型安全:
// 端点A返回的企业基础信息 public class CompanyBasicInfo { public int CompanyId { get; set; } public string CompanyName { get; set; } public string Address { get; set; } public string Contact { get; set; } } // 端点B返回的企业经营信息 public class CompanyBusinessInfo { public int CompanyId { get; set; } public string StructureType { get; set; } public int EmployeeCount { get; set; } public decimal Revenue { get; set; } } // 合并后的最终返回模型 public class CompanyCombinedInfo { public int CompanyId { get; set; } public string CompanyName { get; set; } public string Address { get; set; } public string Contact { get; set; } public string StructureType { get; set; } public int EmployeeCount { get; set; } public decimal Revenue { get; set; } }
2. 并行调用并合并数据
利用HttpClient发起请求,通过Task.WhenAll实现并行调用,再用LINQ合并结果:
private readonly HttpClient _httpClient; // 构造函数注入HttpClient public YourController(HttpClient httpClient) { _httpClient = httpClient; } [HttpGet("combined-company-info")] public async Task<IActionResult> GetCombinedInfo(string city, List<int> companyIds = null) { // 构造请求参数(与A、B端点参数格式一致) var queryParams = new Dictionary<string, string> { { "city", city } }; if (companyIds?.Any() == true) { queryParams.Add("companyIds", string.Join(",", companyIds)); } // 构建A、B端点的请求URL(根据实际地址调整) var urlBuilder = new UriBuilder("https://your-api-domain.com/api/endpointA"); urlBuilder.Query = new FormUrlEncodedContent(queryParams).ReadAsStringAsync().Result; var urlA = urlBuilder.ToString(); var urlB = urlBuilder.ToString().Replace("endpointA", "endpointB"); // 并行调用两个端点,减少等待时间 var taskGetBasic = _httpClient.GetFromJsonAsync<List<CompanyBasicInfo>>(urlA); var taskGetBusiness = _httpClient.GetFromJsonAsync<List<CompanyBusinessInfo>>(urlB); await Task.WhenAll(taskGetBasic, taskGetBusiness); var basicInfos = taskGetBasic.Result; var businessInfos = taskGetBusiness.Result; // 用CompanyId关联合并数据 var combinedResult = basicInfos.Join( businessInfos, basic => basic.CompanyId, business => business.CompanyId, (basic, business) => new CompanyCombinedInfo { CompanyId = basic.CompanyId, CompanyName = basic.CompanyName, Address = basic.Address, Contact = basic.Contact, StructureType = business.StructureType, EmployeeCount = business.EmployeeCount, Revenue = business.Revenue }).ToList(); return Ok(combinedResult); }
简便的JSON动态合并方法
如果不想用强类型(不推荐,缺乏类型安全),可以用JSON库直接合并JSON对象:
方法1:使用Newtonsoft.Json(Json.NET)
// 获取A、B端点的JSON字符串 string jsonBasic = await _httpClient.GetStringAsync(urlA); string jsonBusiness = await _httpClient.GetStringAsync(urlB); var jArrayBasic = JArray.Parse(jsonBasic); var jArrayBusiness = JArray.Parse(jsonBusiness); // 将B的结果转成以CompanyId为键的字典,方便快速查找 var businessDict = jArrayBusiness.ToDictionary(j => (int)j["CompanyId"], j => j); var combinedArray = new JArray(); foreach (var basicObj in jArrayBasic) { int companyId = (int)basicObj["CompanyId"]; if (businessDict.TryGetValue(companyId, out var businessObj)) { // 合并两个JObject,跳过重复的CompanyId var combinedObj = new JObject(basicObj); foreach (var prop in businessObj.Properties()) { if (prop.Name != "CompanyId") { combinedObj[prop.Name] = prop.Value; } } combinedArray.Add(combinedObj); } } return Ok(combinedArray);
方法2:使用System.Text.Json(.NET Core 3.0+内置)
string jsonBasic = await _httpClient.GetStringAsync(urlA); string jsonBusiness = await _httpClient.GetStringAsync(urlB); var jsonArrayBasic = JsonNode.Parse(jsonBasic) as JsonArray; var jsonArrayBusiness = JsonNode.Parse(jsonBusiness) as JsonArray; // 构建B结果的字典 var businessDict = jsonArrayBusiness.ToDictionary( node => (int)node["CompanyId"], node => node as JsonObject); var combinedArray = new JsonArray(); foreach (var basicNode in jsonArrayBasic) { var basicObj = basicNode as JsonObject; int companyId = (int)basicObj["CompanyId"]; if (businessDict.TryGetValue(companyId, out var businessObj)) { // 合并对象 var combinedObj = new JsonObject(); // 添加基础信息 foreach (var kvp in basicObj) { combinedObj.Add(kvp.Key, kvp.Value); } // 添加经营信息(跳过重复键) foreach (var kvp in businessObj) { if (!combinedObj.ContainsKey(kvp.Key)) { combinedObj.Add(kvp.Key, kvp.Value); } } combinedArray.Add(combinedObj); } } return Ok(combinedArray);
注意事项
- 异常处理:给HttpClient调用添加try-catch,处理端点请求失败、数据解析错误等情况
- 空值兼容:合并时要考虑某公司在A或B中不存在的场景,可选择跳过该条目或填充默认值
- 参数一致性:确保传给A、B的请求参数完全一致,避免出现数据不匹配问题
内容的提问来源于stack exchange,提问作者Newbie
相关产品推荐
相关产品推荐

