如何配置TokenAcquirerFactory的basePath?Azure DevOps管道运行报错
我有一个本地运行正常的.NET Core 7控制台应用,基于Azure AD daemon示例项目改造。将其部署到Azure DevOps自托管代理管道运行时,调用TokenAcquirerFactory.GetDefaultInstance()触发“basePath不能为null”的异常。我尝试添加自定义配置构建器读取appsettings.json与环境变量,但问题依旧。我不太熟悉.NET Core依赖注入,且未找到TokenAcquirerFactory的完善配置文档,希望获取配置指导,偏好使用环境变量而非配置文件。
相关代码:
using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Graph; using Microsoft.Identity.Abstractions; using Microsoft.Identity.Web; using System; using System.Threading.Tasks; namespace daemon_console { class CheckCertExpirationDate { static async Task Main(string[] _) { // added from here var builder = new ConfigurationBuilder() .SetBasePath(System.IO.Directory.GetCurrentDirectory()) .AddJsonFile("appsettings.json") .AddEnvironmentVariables(); var configuration = builder.Build(); // this outputs to true so I know the file exists Console.WriteLine(System.IO.File.Exists("appsettings.json")); // added to here // error occurs on the line below TokenAcquirerFactory tokenAcquirerFactory = TokenAcquirerFactory.GetDefaultInstance(); IServiceCollection services = tokenAcquirerFactory.Services; services.AddMicrosoftGraph(); var serviceProvider = tokenAcquirerFactory.Build(); try { GraphServiceClient graphServiceClient = serviceProvider.GetRequiredService<GraphServiceClient>(); var cert = await graphServiceClient.DeviceManagement.ApplePushNotificationCertificate.Request().WithAppOnly().GetAsync(); Console.WriteLine(cert.ExpirationDateTime); Console.WriteLine($"{cert.ExpirationDateTime}"); } catch (ServiceException e) { Console.WriteLine("We could not retrieve the expiration date: " + $"{e}"); } } } }
报错信息:
Unhandled exception. System.ArgumentNullException: Value cannot be null. (Parameter 'basePath') at System.ThrowHelper.Throw(String paramName) at Microsoft.Extensions.Configuration.FileConfigurationExtensions.SetBasePath(IConfigurationBuilder builder, String basePath) at Microsoft.Identity.Web.TokenAcquirerFactory.ReadConfiguration() at Microsoft.Identity.Web.TokenAcquirerFactory.GetDefaultInstance(String configSection) at daemon_console.CheckCertExpirationDate.Main(String[] _) in D:\a\1\s\CheckCertExpirationDate\CheckCertExpirationDate\CheckCertExpirationDate.cs:line 34 at daemon_console.CheckCertExpirationDate.<Main>(String[] _)
问题根源
TokenAcquirerFactory.GetDefaultInstance()内部会自动尝试读取配置文件,但在Azure DevOps自托管代理的运行环境中,当前工作目录的basePath可能为空或无法正常访问,导致其调用SetBasePath时传入null值,触发异常。你手动创建的ConfigurationBuilder并没有被TokenAcquirerFactory使用,所以无法解决问题。
修复步骤
1. 手动传入自定义配置给TokenAcquirerFactory
放弃使用GetDefaultInstance(),改为手动实例化TokenAcquirerFactory并传入你构建好的配置对象,这样就能完全控制配置来源(优先使用环境变量)。
2. 修改后的代码
using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Graph; using Microsoft.Identity.Abstractions; using Microsoft.Identity.Web; using System; using System.Threading.Tasks; namespace daemon_console { class CheckCertExpirationDate { static async Task Main(string[] _) { // 构建配置:优先环境变量,其次配置文件 var builder = new ConfigurationBuilder() .SetBasePath(System.IO.Directory.GetCurrentDirectory()) .AddJsonFile("appsettings.json", optional: true) // 标记为可选,避免无文件时报错 .AddEnvironmentVariables(); // 环境变量优先级高于配置文件 var configuration = builder.Build(); // 手动创建TokenAcquirerFactory,传入自定义配置 var tokenAcquirerFactory = TokenAcquirerFactory.Create(configuration); // 注册Graph服务 tokenAcquirerFactory.Services.AddMicrosoftGraph(); var serviceProvider = tokenAcquirerFactory.Build(); try { GraphServiceClient graphServiceClient = serviceProvider.GetRequiredService<GraphServiceClient>(); var cert = await graphServiceClient.DeviceManagement.ApplePushNotificationCertificate.Request().WithAppOnly().GetAsync(); Console.WriteLine(cert.ExpirationDateTime); } catch (ServiceException e) { Console.WriteLine("无法获取证书过期日期: " + $"{e}"); } } } }
3. 环境变量配置规则
环境变量需要遵循Microsoft Identity Web的命名规范,使用双下划线__替代配置文件中的层级结构,示例如下:
AzureAd__TenantId: 你的Azure AD租户IDAzureAd__ClientId: 应用注册的客户端IDAzureAd__ClientSecret: 应用注册的客户端密钥(使用密钥认证时)DownstreamApi__BaseUrl:https://graph.microsoft.com/v1.0DownstreamApi__Scopes:https://graph.microsoft.com/.default
如果使用证书认证,可配置以下环境变量:
AzureAd__Certificate__Thumbprint: 证书指纹AzureAd__Certificate__Path: 证书文件路径(代理环境中确保路径可访问)
4. Azure DevOps代理配置
在Azure DevOps管道中,可通过变量组或任务变量设置上述环境变量,确保运行时能正确读取。
内容的提问来源于stack exchange,提问作者Joshua K

