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

macOS上.NET无法解析Azure CNAME(AI AgentsClient),A记录及系统工具正常

macOS上.NET无法解析Azure CNAME域名的问题排查

环境

  • MacBook Air(Apple Silicon,arm64)
  • macOS 15.4.1(Sonoma)
  • .NET SDK 9.0.203、.NET Runtime 9.0.4(osx-arm64)
  • 无VPN、防火墙或安全软件干扰
  • DNS设置为Google(8.8.8.8)
  • 使用基于DefaultAzureCredential的Azure SDK客户端代码

问题描述

运行连接Azure AI Agents服务API端点eastus.api.azureml.ms的.NET应用时,出现DNS解析失败:.NET无法解析该CNAME域名,但终端通过dig工具可正常解析完整CNAME链,且.NET能正常解析其他域名(如www.google.com)及该CNAME对应的最终A记录(vienna-eastus-ip-ingress-nginx-02.eastus.cloudapp.azure.com)。

示例输出

[DEBUG] .NET DNS test for eastus.api.azureml.ms
[DEBUG] .NET DNS resolution failed: nodename nor servname provided, or not known
[DEBUG] .NET DNS test for vienna-eastus-ip-ingress-nginx-02.eastus.cloudapp.azure.com
[DEBUG] .NET DNS resolved: 48.211.42.162
[DEBUG] .NET DNS test for www.google.com
[DEBUG] .NET DNS resolved: 142.250.72.100

Azure SDK错误信息

❌ Error occurred: Retry failed after 2 tries. Retry settings can be adjusted in ClientOptions.Retry or by configuring a custom retry policy in ClientOptions.RetryPolicy. (nodename nor servname provided, or not known (eastus.api.azureml.ms:443))
[DEBUG] Exception Type: System.AggregateException
[DEBUG] Inner Exception: nodename nor servname provided, or not known (eastus.api.azureml.ms:443)
[DEBUG] Inner Exception Type: Azure.RequestFailedException

已尝试的措施

  • 确认系统DNS正常(dig可解析完整CNAME链)
  • .NET可正常解析www.google.com及该CNAME对应的最终A记录
  • 禁用所有VPN、防火墙及安全软件
  • 切换至Google DNS(8.8.8.8)
  • 检查/etc/hosts和/etc/resolv.conf配置
  • 使用最新arm64版本的.NET SDK和Runtime
  • 未设置global.json或自定义环境变量
  • 尝试Dns.GetHostAddresses和Dns.GetHostEntry两种解析方法
  • 完成上述操作后重启设备

疑问

为何macOS上的.NET无法解析该Azure CNAME域名?还有哪些可行的排查或修复措施能让.NET正常解析此Azure端点?

代码片段

// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

#nullable disable

using Azure.Identity;
using Azure.Core;
namespace Azure.AI.Projects;

public class Sample_Agent
{
    static async Task Main()
    {
        Console.WriteLine($"Application started at: {DateTime.Now:yyyy-MM-dd HH:mm:ss}");
        Console.WriteLine("Initializing agent configuration...");
        
        // Use explicit connection string as requested
        var connectionString = "<project connection string I scrubbed, format: <HostName>;<AzureSubscriptionId>;<ResourceGroup>;<ProjectName>>";
        Console.WriteLine($"[DEBUG] Using connection string: {connectionString.Substring(0, Math.Min(connectionString.Length, 20))}... (masked)");
        Console.WriteLine($"[DEBUG] Machine Name: {Environment.MachineName}");
        Console.WriteLine($"[DEBUG] OS Version: {Environment.OSVersion}");
        Console.WriteLine($"[DEBUG] Current Directory: {Environment.CurrentDirectory}");
        try
        {
            var host = "eastus.api.azureml.ms";
            Console.WriteLine($"[DEBUG] .NET DNS test for {host}");
            var entry = System.Net.Dns.GetHostEntry(host);
            Console.WriteLine($"[DEBUG] .NET DNS resolved: {entry}");
        }
        catch (Exception ex)
        {
            Console.WriteLine($"[DEBUG] .NET DNS resolution failed: {ex.Message}");
        }
        var options = new AIProjectClientOptions();
        options.Retry.MaxRetries = 1;
        AgentsClient client = new AgentsClient(connectionString, new DefaultAzureCredential(), options);
        
        try 
        {
            Console.WriteLine("[DEBUG] Attempting to retrieve agent by ID");
            Response<Agent> agentResponse = await client.GetAgentAsync("<agent id I scrubbed>");
            Agent agent = agentResponse.Value;
            Console.WriteLine($"✓ Agent retrieved successfully (ID: {agent.Id})");

            // Verify agent in list
            Console.WriteLine("\nVerifying agent in list...");
            Response<PageableList<Agent>> agentListResponse = await client.GetAgentsAsync();
            Console.WriteLine($"✓ Found {agentListResponse.Value.Data.Count} agent(s) in total");

            // Step 2: Create a thread
            Console.WriteLine("\n=== Creating Thread ===");
            Response<AgentThread> threadResponse = await client.CreateThreadAsync();
            AgentThread thread = threadResponse.Value;
            Console.WriteLine($"✓ Thread created successfully (ID: {thread.Id})");

            // Step 3: Add a message
            Console.WriteLine("\n=== Adding Message to Thread ===");
            string userMessage = "I need to solve the equation `3x + 11 = 14`. Can you help me?";
            Console.WriteLine($"User message: {userMessage}");
            Response<ThreadMessage> messageResponse = await client.CreateMessageAsync(
                thread.Id,
                MessageRole.User,
                userMessage);
            ThreadMessage message = messageResponse.Value;
            Console.WriteLine($"✓ Message added successfully (ID: {message.Id})");

            // Verify message in thread
            Console.WriteLine("\nVerifying message in thread...");
            Response<PageableList<ThreadMessage>> messagesListResponse = await client.GetMessagesAsync(thread.Id);
            Console.WriteLine($"✓ Found {messagesListResponse.Value.Data.Count} message(s) in thread");

            // Step 4: Run the agent
            Console.WriteLine("\n=== Starting Agent Run ===");
            Response<ThreadRun> runResponse = await client.CreateRunAsync(
                thread.Id,
                agent.Id,
                additionalInstructions: "");
            ThreadRun run = runResponse.Value;
            Console.WriteLine($"✓ Run initiated (ID: {run.Id})");

            // Monitor run progress
            int pollCount = 0;
            Console.WriteLine("\nMonitoring run progress:");
            do
            {
                pollCount++;
                Console.WriteLine($"[{DateTime.Now:HH:mm:ss}] Status: {runResponse.Value.Status} (Poll #{pollCount})");
                await Task.Delay(TimeSpan.FromMilliseconds(500));
                runResponse = await client.GetRunAsync(thread.Id, runResponse.Value.Id);
            }
            while (runResponse.Value.Status == RunStatus.Queued
                || runResponse.Value.Status == RunStatus.InProgress);

            Console.WriteLine($"\n✓ Run completed with status: {runResponse.Value.Status}");
            if (runResponse.Value.LastError != null)
            {
                Console.WriteLine($"⚠ Last error: {runResponse.Value.LastError.Message}");
            }

            // Get final messages
            Console.WriteLine("\n=== Final Message History ===");
            Response<PageableList<ThreadMessage>> afterRunMessagesResponse = await client.GetMessagesAsync(thread.Id);
            IReadOnlyList<ThreadMessage> messages = afterRunMessagesResponse.Value.Data;
            Console.WriteLine($"Retrieved {messages.Count} total messages\n");

            Console.WriteLine("Message Timeline:");
            Console.WriteLine("----------------");
            foreach (ThreadMessage threadMessage in messages)
            {
                Console.WriteLine($"\n[{threadMessage.CreatedAt:yyyy-MM-dd HH:mm:ss}]");
                Console.WriteLine($"Role: {threadMessage.Role}");
                Console.WriteLine("Content:");
                foreach (MessageContent contentItem in threadMessage.ContentItems)
                {
                    if (contentItem is MessageTextContent textItem)
                    {
                        Console.WriteLine($"  {textItem.Text}");
                    }
                    else if (contentItem is MessageImageFileContent imageFileItem)
                    {
                        Console.WriteLine($"  <image from ID: {imageFileItem.FileId}>");
                    }
                }
                Console.WriteLine("----------------");
            }
        }
        catch (Exception ex)
        {
            Console.WriteLine($"\n❌ Error occurred: {ex.Message}");
            Console.WriteLine($"[DEBUG] Exception Type: {ex.GetType().FullName}");
            Console.WriteLine($"[DEBUG] Stack trace: {ex.StackTrace}");
            if (ex.InnerException != null)
            {
                Console.WriteLine($"[DEBUG] Inner Exception: {ex.InnerException.Message}");
                Console.WriteLine($"[DEBUG] Inner Exception Type: {ex.InnerException.GetType().FullName}");
                Console.WriteLine($"[DEBUG] Inner Exception Stack trace: {ex.InnerException.StackTrace}");
            }
            if (ex is Azure.RequestFailedException reqEx)
            {
                Console.WriteLine($"[DEBUG] Azure RequestFailedException Status: {reqEx.Status}");
                Console.WriteLine($"[DEBUG] Azure RequestFailedException ErrorCode: {reqEx.ErrorCode}");
            }
        }
        
        Console.WriteLine($"\nApplication completed at: {DateTime.Now:yyyy-MM-dd HH:mm:ss}");
    }
}

排查与修复措施

可能原因

  1. .NET DNS解析机制差异:.NET在macOS上可能使用与系统dig不同的解析路径,比如直接调用系统API而非读取resolv.conf,对CNAME链的兼容性处理存在差异。
  2. DNS缓存冲突:系统或.NET自身的DNS缓存存在过期/错误记录,导致dig能获取新结果,但.NET仍读取旧缓存。
  3. IPv6优先级问题:该域名的IPv6记录存在但不可达,.NET优先尝试IPv6解析失败,而dig默认返回IPv4结果。

具体修复步骤

  1. 强制.NET使用IPv4解析
    在代码中指定仅解析IPv4:

    var addresses = System.Net.Dns.GetHostAddresses(host, System.Net.Sockets.AddressFamily.InterNetwork);
    

    或通过环境变量全局禁用IPv6后运行应用:

    export DOTNET_SYSTEM_NET_DNS_DISABLE_IPV6=true
    dotnet run
    
  2. 清除.NET DNS缓存

    • 直接重启应用(简单有效)
    • 调试场景下可通过反射清理内部缓存:
      typeof(System.Net.Dns).GetMethod("FlushCache", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Static).Invoke(null, null);
      
  3. 手动指定DNS服务器
    引用第三方DnsClient NuGet包,配置.NET使用指定DNS服务器:

    var dnsClient = new DnsClient.DnsClient("8.8.8.8");
    var result = await dnsClient.QueryAsync(host, DnsClient.QueryType.A);
    
  4. 添加临时hosts映射
    在/etc/hosts中添加域名与A记录的映射,绕过DNS解析:

    48.211.42.162 eastus.api.azureml.ms
    

    添加后执行sudo dscacheutil -flushcache刷新系统缓存。

  5. 检查CNAME链完整性
    使用dig +trace eastus.api.azureml.ms查看完整解析链,确认所有中间CNAME记录均有效,若存在无效记录需联系Azure支持修正。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.13 04:25:55