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

如何配置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租户ID
  • AzureAd__ClientId: 应用注册的客户端ID
  • AzureAd__ClientSecret: 应用注册的客户端密钥(使用密钥认证时)
  • DownstreamApi__BaseUrl: https://graph.microsoft.com/v1.0
  • DownstreamApi__Scopes: https://graph.microsoft.com/.default

如果使用证书认证,可配置以下环境变量:

  • AzureAd__Certificate__Thumbprint: 证书指纹
  • AzureAd__Certificate__Path: 证书文件路径(代理环境中确保路径可访问)

4. Azure DevOps代理配置

在Azure DevOps管道中,可通过变量组或任务变量设置上述环境变量,确保运行时能正确读取。

内容的提问来源于stack exchange,提问作者Joshua K

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.23 19:09:51