HttpWebRequest在几个滴答声之后中断了计时器滴答声事件

时间:2019-03-29 14:40:15

标签: c# windows winforms httpwebrequest

我有一个针对.NET 4.0的Windows Forms应用程序,该应用程序在具有.NET 4.0最新版本的x64 Windows Server 2012 R2服务器上运行。为了将请求发送到服务器(在全国范围内使用),您需要在请求的标头中添加会话令牌(从服务器获取)。根据官方文档从服务器获取令牌:

bool ServerCertificateBypass(object sender,
                             X509Certificate certificate,
                             X509Chain chain,
                             SslPolicyErrors sslPolicyErrors)
{
    return true;
} 

public string AcquireToken (X509Certificate userCertificate, 
              string password, string userName) 
{
    // configure general http options
    ServicePointManager.ServerCertificateValidationCallback = ServerCertificateBypass;
    ServicePointManager.SecurityProtocol = SecurityProtocolType.Ssl3 |
                        SecurityProtocolType.Tls; // default in .NET
    // create https request
    var url = String.Format("https://serveraddress/validator?username={0}", userName);
    var request = (HttpWebRequest)WebRequest.Create(new Uri(url));
    // configure web request
    request.Accept = "*/*";
    request.KeepAlive = true;
    request.AllowAutoRedirect = false;
    request.PreAuthenticate = true;
    // set Internet Explorer proxy
    request.Proxy = ProxyHelper.GetSystemWebProxy();
    // add user certificate
    request.ClientCertificates.Add(userCertificate); // userCertificate is a X509Certificate object
    // add server credentials
    var credentials = new CredentialCache();
    credentials.Add(uri, "Basic", new NetworkCredential(userName.password));
    request.Credentials = credentials;
    // overwrite CookieContainer to store cookies
    request.CookieContainer = CookieJar; // CookieJar is a static CookieContainer object
    // get web response
    var response = request.GetResponse();
    // extract session token
    return response.Headers["SESSION_TOKEN"]; 
}

ServerCertificateBypass是一个始终返回true的委托,而userName和password是字符串变量。会话令牌在一小时后过期,因此我决定使用内部计时器。每当它打勾时,我都会调用上面的函数并获取一个新令牌:

private void timer_Tick(object sender, EventArgs e)
{
    lock (syncLock)
    {
         // stop timer
         timer.Stop();
         // acquire and store token
         Task.Factory.StartNew(() => AcquireToken(Settings.UserCertificate, Settings.Password, Settings.UserName))
                  .ContinueWith(t =>
                  {
                      if (!string.IsNullOrEmpty(t.Result))
                      {
                           SaveToken(t.Result)
                           UpdateUI();
                       }
                   });
         // start timer
         timer.Start();
    }
}

如果我将频率设置为5分钟,则在调用request.GetResponse()时,上面的代码在第6或第7个滴答处正常工作,并且出现以下错误:

  

请求已中止:无法创建SSL / TLS安全通道

如果我重新启动该应用程序,则可以再次正常运行几秒钟。如果我将频率设置为60分钟,则它仅会获得两个滴答声,此后它会因相同的错误而中断。我在UI中还有一个按钮可以手动调用AcquireToken函数。在我收到该错误之前,它一直可以正常工作,直到我重新启动该应用程序为止,该错误也将不起作用。

将ServicePointManager.SecurityProtocol设置为Tls1.1,Tls1.2的任何变体(如The request was aborted: Could not create SSL/TLS secure channel中的建议)不起作用,并且服务器不支持它,因为它不在官方文档中。

问题是,为什么它会在几次正常运行后中断,然后在重新启动应用程序后将无法工作?

感谢您的帮助。

更新:我忘了提到用户证书在2020年之前有效,并且Internet Explorer中启用了SSL3.0和TLS的每个版本。

0 个答案:

没有答案