C# WebClient DownloadFile 只工作一次

C# WebClient DownloadFile works only once

我构建了一个功能,可以从我的网站(.NET 网络表单、旧应用程序)下载一系列报告,将它们另存为临时文件夹中的 .html 文件,压缩它们并 return给用户的存档。 该应用程序使用 windows 身份验证,我通过启用

设法在请求中传递了当前用户凭据
Credentials = CredentialCache.DefaultCredentials

一切都在我的开发环境中无缝运行(在 IIS Express 和 IIS 中),但在生产服务器(Windows 服务器 2008 R2,IIS 7.5)上,它仅在我将周期限制为一次迭代时才有效只要。 看起来 WebClient 底层连接保持打开状态,服务器拒绝在下一个周期打开另一个连接。 我收到的错误消息是

The request was aborted: Could not create SSL/TLS secure channel.

并且,启用 WCF 跟踪,我可以将问题缩小为“401 未授权”错误。

这是我函数的重要部分:

ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls | 
                                       SecurityProtocolType.Tls12 | 
                                       SecurityProtocolType.Tls11;
foreach (var project in list.Take(1)) //fails if I try list.Take(2) or more
{
    using (WebClient client = new WebClient
    {
        Credentials = CredentialCache.DefaultCredentials
    })
    {       
        UriBuilder address = new UriBuilder
        {
            Scheme = Request.Url.Scheme,
            Host = Request.Url.Host,
            Port = Request.Url.Port,
            Path = "/ERP_ProjectPrint.aspx",
            Query = string.Format("bpId={0}&bpVid={1}", project.Id, project.VersionId)
        };
        string fileName = project.VersionProtocol + ".html";
        client.DownloadFile(address.Uri.ToString(), tempFilePath + fileName);       
    }
}

关于 IIS 设置的任何提示我可以调整以解决此问题?

尝试将循环移动到您的请求中,如下所示。这有什么区别吗?

也不认为你需要使用list.Take

ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls | 
                                   SecurityProtocolType.Tls12 | 
                                   SecurityProtocolType.Tls11;

System.Net.ServicePointManager.DefaultConnectionLimit = 10

using (WebClient client = new WebClient
{
    Credentials = CredentialCache.DefaultCredentials
}) 
   {                                         
     foreach (var project in list) 
     {

        UriBuilder address = new UriBuilder
        {
            Scheme = Request.Url.Scheme,
            Host = Request.Url.Host,
            Port = Request.Url.Port,
            Path = "/ERP_ProjectPrint.aspx",
            Query = string.Format("bpId={0}&bpVid={1}", project.Id, project.VersionId)
        };
        string fileName = project.VersionProtocol + ".html";
        client.DownloadFileTaskAsync(address.Uri.ToString(), tempFilePath + fileName).Wait();
      }
   }
}

问题已通过在服务器上启用 TLS 1.2 得到解决:默认情况下未启用。参考https://tecadmin.net/enable-tls-on-windows-server-and-iis/.

请注意,启用它可能会破坏与服务器的 RDP 连接功能。

感谢 Jokies Ding 为我指明了正确的方向(见上面的评论)

在 using() 语句中 Dispose() 似乎无法正常工作:

using (WebClient client = new WebClient())
 { ... }

没有 using() 语句的解决方法:

WebClient client = new WebClient();
client.DownloadFileCompleted += OnDownloadFileCompleted;

下载完成时:

client.Dispose() 

对我有用。