如何使用C#以编程方式查找并调用指定区域的Azure Function
C# 基于MSI认证按指定区域调用Azure Function实现方案
前置准备
- 提前维护区域参数与对应Azure Function部署实例的根地址映射,例如
useast2对应https://<your-func-app-name>-useast2.azurewebsites.net,映射关系建议存在环境变量、应用配置服务或配置文件中,禁止硬编码在业务逻辑内。 - 为调用方配置的托管标识(系统分配/用户分配MSI)授予所有跨区域部署Function实例的调用权限:若Function开启了AAD身份验证,需将MSI对应的服务主体添加到每个Function实例的授权列表中,授予接口调用权限,避免鉴权失败。
- 项目引入必需的NuGet包:
Azure.Identity(用于获取MSI令牌)、System.Text.Json(用于请求序列化,可根据项目习惯替换为其他序列化库)。
核心实现代码
首先维护区域-端点映射,生产环境请替换为从配置中心读取:
// 示例为硬编码映射,生产环境从配置加载 private static readonly IReadOnlyDictionary<string, string> RegionEndpointMapping = new Dictionary<string, string> { ["useast2"] = "https://your-func-useast2.azurewebsites.net", ["westeurope"] = "https://your-func-westeurope.azurewebsites.net", ["chinaeast2"] = "https://your-func-chinaeast2.chinacloudsites.cn" // 按实际部署补充所有区域对应地址 };
封装区域调用方法:
// 生产环境建议用IHttpClientFactory创建HttpClient实例做复用 private static readonly HttpClient _httpClient = new HttpClient(); /// <summary> /// 按指定区域调用Azure Function /// </summary> /// <param name="region">区域参数,例如useast2</param> /// <param name="apiRoute">Function接口路由,例如/api/OrderProcess</param> /// <param name="payload">请求参数</param> /// <param name="userAssignedMsiClientId">用户分配MSI的客户端ID,用系统分配MSI可传null</param> /// <param name="ct">取消令牌</param> public async Task<string> CallFunctionByRegionAsync(string region, string apiRoute, object payload, string? userAssignedMsiClientId = null, CancellationToken ct = default) { // 校验区域参数,解析目标请求地址 if (!RegionEndpointMapping.TryGetValue(region.ToLowerInvariant(), out var funcBaseAddress)) { throw new ArgumentOutOfRangeException(nameof(region), $"未找到区域{region}对应的Function部署实例"); } var requestUri = new Uri(new Uri(funcBaseAddress), apiRoute.TrimStart('/')); // 获取MSI访问令牌 var credentialOptions = new DefaultAzureCredentialOptions(); if (!string.IsNullOrEmpty(userAssignedMsiClientId)) { credentialOptions.ManagedIdentityClientId = userAssignedMsiClientId; } // 若涉及Azure中国、美国政府等独立云环境,此处需配置对应AuthorityHost var credential = new DefaultAzureCredential(credentialOptions); // 请求令牌的scope固定格式为 {Function根地址}/.default var tokenResult = await credential.GetTokenAsync(new TokenRequestContext(new[] { $"{funcBaseAddress}/.default" }), ct); // 构造请求发送 using var request = new HttpRequestMessage(HttpMethod.Post, requestUri); request.Headers.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", tokenResult.Token); request.Content = new StringContent(JsonSerializer.Serialize(payload), Encoding.UTF8, "application/json"); using var response = await _httpClient.SendAsync(request, ct); response.EnsureSuccessStatusCode(); return await response.Content.ReadAsStringAsync(ct); }
关键注意事项
DefaultAzureCredential会自动适配运行环境:本地调试时会自动读取Visual Studio、Azure CLI、VS Code的登录凭据获取令牌,部署到Azure服务(VM、App Service、AKS等)后会自动使用MSI获取令牌,不需要额外写环境判断逻辑。- 若Function部署在Azure私有网络(VNet)内,需要确保调用方所在网络能通过私有链路访问到对应区域Function的私有端点,否则会出现网络不通的问题。
Azure.Identity内置了令牌缓存和自动刷新逻辑,不需要手动实现令牌过期处理,不要每次调用都重复创建DefaultAzureCredential实例,避免重复请求令牌接口产生限流。- 如果使用Function部署槽位做预发布验证,只需要在区域映射表中补充槽位对应的完整地址(例如
https://your-func-useast2-staging.azurewebsites.net),其余逻辑无需修改。
内容的提问来源于stack exchange,提问作者Aarthi Vishwanathan
相关产品推荐
相关产品推荐

