检测 .Net Core 中的 Windows 代理设置

Mat*_*ier 1 .net .net-core

我们的一台测试服务器具有代理设置,我能够使用 1 行 powershell 命令检测要使用的代理。

 (new-object System.Net.WebClient).Proxy.GetProxy("https://www.google.com")
Run Code Online (Sandbox Code Playgroud)

但是,如果我在 .Net Core 中实例化 WebClient 对象,则代理为 null。我们当前的解决方案是简单地为所有传出连接设置代理作为环境配置的一部分。这对于我们的一些更简单的服务来说效果很好,这些服务只联系一个需要代理的端点,但是我现在正在研究一种修复方法,其中一个端点需要代理,而另一个端点则不需要。

我的选择是

  1. 添加不被代理的端点的排除列表
  2. 以某种方式从操作系统获取代理设置

这个问题正在寻求第 2 号的帮助。我可以毫无问题地实施选项 1。

我最好的猜测是,由于 .Net 架构的变化,代理信息不可用。我发现了以下有启发性的引述。( https://github.com/dotnet/runtime/issues/24756 ) 我们使用 dot net core 3。

从 .NET Core 2.1 开始,.NET Core 中使用的 HTTP 协议栈已更改。它不再使用本机 Windows WinHTTP 或 Linux 'libcurl'。这些现在被认为是“遗留”堆栈。我们有一个新的 HTTP 协议栈,称为“SocketsHttpHandler”。默认情况下使用它。

所以基本上我认为我正在寻找一些神奇的代码来从旧的 Windows 网络堆栈中获取代理信息(如果在 Windows 上运行)。

bool isWindows = System.Runtime.InteropServices.RuntimeInformation
                                               .IsOSPlatform(OSPlatform.Windows);

if (isWindows) {
   // Do magic get proxy settings secret sauce.
}
Run Code Online (Sandbox Code Playgroud)

Mat*_*ier 5

最终我确定 powershell 脚本的“系统”配置来自框架安装中的旧配置文件。

C:\Windows\Microsoft.NET\Framework\v4.0.30319\Config\machine.config

<system.net>  
    <defaultProxy>
        <proxy
            usesystemdefault="false"
            proxyaddress="http://proxy.internal.local"
            bypassonlocal="true"
        />
        <bypasslist>
            <add address="someServer.com" />
            <add address="someotherserver.com" />
        </bypasslist>
    </defaultProxy>
</system.net>
Run Code Online (Sandbox Code Playgroud)

初始解决方案

这是我们在.Net core中使用的最初的解决方案。后来我们发现.Net Core代码支持HTTPS_PROXY和NO_PROXY变量,向下滚动可以看到最终的解决方案。

首先我们将以下设置添加到appsettings.json

"proxy": {
  "address": "http://proxy.internal.local",
  "bypasslist": [
    "someServer.com",
    "someotherserver.com"
  ]
}  
Run Code Online (Sandbox Code Playgroud)

然后我们使用以下 C# 代码来加载设置。

    private static void ConfigureProxy()
    {

        IConfigurationSection proxySection = configuration.GetSection("proxy");

        if ( ! proxySection.Exists() ) {
            return;  // A proxy is not configured.  Do nothing.
        }

        string proxyUrl = proxySection["address"];

        if ( proxyUrl == null )
        {
            Logger.LogWarning("Detected a proxy configuration section without a proxy address.  Review your configuration.");
            return;
        }

        string[] bypasslist = proxySection.GetSection("bypasslist")
                                    .GetChildren()
                                    .Select(x => x.Value)
                                    .ToArray();

        WebProxy proxyObject;
        
        if ( bypasslist.Length > 0 ) {
            proxyObject = new WebProxy(proxyUrl,true, bypasslist);
        } else {
            Logger.LogWarning("Creating proxy with no bypass list");
            proxyObject = new WebProxy(proxyUrl,true);
        }
                   
        WebRequest.DefaultWebProxy = proxyObject;
        Logger.LogInformation($"WebRequest.DefaultWebProxy set to {proxyUrl}");
    }
Run Code Online (Sandbox Code Playgroud)

此解决方案的好处是,您可以在 appsettings.json 中看到代理设置(如果您的代理设置是这样的话)。

最终解决方案

因此,如果您想在 appsettings.json 中支持代理信息,那么这是一个解决方案。不过还有另一种方法。您只需使用 HTTPS_PROXY 和 NO_PROXY 环境变量即可,Microsoft 代码将为您配置代理。

$env:HTTPS_PROXY = 'http://proxy.internal.local'
$env:NO_PROXY = '.someServer.com,.someotherserver.com'
RunYourApplication
Run Code Online (Sandbox Code Playgroud)

请注意 NO_PROXY 格式。它是一个逗号分隔的列表,域名必须以点为前缀。