C# Azure Function返回资源组及列表异常问题排查
正在开发基于Azure Functions的API,需要实现两类查询逻辑:
- 传入订阅ID、不指定资源组名时,返回对应订阅下的所有资源组名称列表
- 传入订阅ID+资源组名时,返回指定资源组的ID
现有代码实现如下:
[Function("getRg")] public async Task<HttpResponseData> GetRgs([HttpTrigger(AuthorizationLevel.Function, "get", Route = "rg")] HttpRequestData req, string? rg, string sub, FunctionContext functionContext) { ArmClient client = new ArmClient(new DefaultAzureCredential()); SubscriptionCollection subscriptions = client.GetSubscriptions(); SubscriptionResource subscription = await subscriptions.GetAsync(sub); ResourceGroupCollection resourceGroups = subscription.GetResourceGroups(); if (!string.IsNullOrEmpty(rg)) { string resJson = ""; ResourceGroupResource resourceGroup = await resourceGroups.GetAsync(rg); resourceGroup = await resourceGroup.GetAsync(); resJson = JsonSerializer.Serialize(resourceGroup.Data.Id); _logger.LogInformation($"requested RG: ${resJson}"); var response = req.CreateResponse(HttpStatusCode.OK); response.Headers.Add("Content-Type", "text/plain; charset=utf-8"); response.WriteString(resJson); return response; } else { var rgList = new List<string>(); foreach (var rgItem in resourceGroups) { rgList.Add(rgItem.Data.Name); } _logger.LogInformation($"rg list: {rgList}"); var response = req.CreateResponse(HttpStatusCode.OK); response.Headers.Add("Content-Type", "text/html, charset=utf-8"); await response.WriteAsJsonAsync(rgList); return response; } }
- 不传入rg参数查询资源组列表时,函数抛出异常:
System.Private.CoreLib: Exception while executing function: Functions.getRg. System.Private.CoreLib: Result: Failure
Exception: System.AggregateException: One or more errors occurred. (The format of value 'text/plain, charset=utf-8' is invalid.)
- 查询单个资源组ID时,预期仅返回资源ID字符串,实际返回了体积很大的完整对象结构,不符合预期。
问题1:响应头格式错误+枚举逻辑错误
Content-Type是HTTP标准头,格式要求为MIME类型; 参数键=参数值,MIME类型和charset参数之间必须用分号分隔,不能使用逗号。
现有代码列表分支存在两个明确错误:
- 用逗号分隔
text/html和charset=utf-8,直接触发头格式校验异常 - 返回JSON结构时误用
text/html作为MIME类型,JSON对应的标准MIME类型是application/json
额外注意两个细节:
WriteAsJsonAsync方法运行时会自动写入正确的application/json; charset=utf-8头,不需要手动添加该头,避免重复设置或格式写错ResourceGroupCollection是SDK返回的异步分页集合AsyncPageable<ResourceGroupResource>,不能直接用同步foreach遍历,必须用await foreach做异步枚举,否则会出现枚举异常
问题2:序列化对象类型错误
resourceGroup.Data.Id是Azure SDK封装的ResourceIdentifier复杂类型,不是原生字符串。直接把这个对象传给JsonSerializer.Serialize时,序列化器会递归序列化该类型的所有公共属性,最终输出完整的大对象结构。如果只需要返回资源ID字符串,直接调用ResourceIdentifier.ToString()拿到ID的字符串表现形式即可,不需要序列化整个复杂对象。
另外单资源组分支中resourceGroup = await resourceGroup.GetAsync();属于冗余代码,resourceGroups.GetAsync(rg)已经返回了目标资源组实例,重复调用GetAsync会发起一次不必要的Azure管理API请求,可以直接删除。
[Function("getRg")] public async Task<HttpResponseData> GetRgs([HttpTrigger(AuthorizationLevel.Function, "get", Route = "rg")] HttpRequestData req, string? rg, string sub, FunctionContext functionContext) { ArmClient client = new ArmClient(new DefaultAzureCredential()); SubscriptionCollection subscriptions = client.GetSubscriptions(); SubscriptionResource subscription = await subscriptions.GetAsync(sub); ResourceGroupCollection resourceGroups = subscription.GetResourceGroups(); if (!string.IsNullOrEmpty(rg)) { ResourceGroupResource resourceGroup = await resourceGroups.GetAsync(rg); // 直接取资源ID的字符串形式,避免序列化复杂对象 string rgId = resourceGroup.Data.Id.ToString(); _logger.LogInformation($"requested RG: {rgId}"); var response = req.CreateResponse(HttpStatusCode.OK); response.Headers.Add("Content-Type", "text/plain; charset=utf-8"); response.WriteString(rgId); return response; } else { var rgList = new List<string>(); // 异步分页集合必须用await foreach遍历 await foreach (var rgItem in resourceGroups) { rgList.Add(rgItem.Data.Name); } _logger.LogInformation($"rg list: {rgList}"); var response = req.CreateResponse(HttpStatusCode.OK); // WriteAsJsonAsync自动设置正确的Content-Type,无需手动添加 await response.WriteAsJsonAsync(rgList); return response; } }
内容的提问来源于stack exchange,提问作者Renm

