简体   繁体   English

C#-Windows窗体-如何从任务中捕获未处理的异常

[英]C# - windows form - how to catch an unhandled exception from a task

Im using a BCrypt Nuget package to create a windows forms application with some encryption. 我使用BCrypt Nuget包来创建带有某种加密的Windows窗体应用程序。 The package uses the "Verify" method to check for a password and a hash. 该程序包使用“验证”方法来检查密码和哈希。 The "Verify" method returns true if the password and the hash match.I'm trying to add some functionality to the form by executing some things while the "Verify" method is called. 如果密码和哈希匹配,则“ Verify”方法返回true。我试图通过在调用“ Verify”方法时执行一些操作来向表单添加一些功能。

So I have used it as a task, when i use a proper bcrypt hash which begins with "$2$" as the input to compare, the code works normal. 因此,我已将其用作任务,当我使用以“ $ 2 $”开头的适当bcrypt哈希作为要比较的输入时,代码可以正常工作。 But when a random input is given, the package recognizes an invalid salt and a saltParseException is throwed by the package, the program crashes with the error saying that the exception is unhandled. 但是,当给出随机输入时,程序包将识别出无效的salt,并且该程序包将抛出saltParseException,程序崩溃,并显示错误消息,指出未处理该异常。 I tried adding a saltParaseException handling but it still won't work. 我尝试添加saltParaseException处理,但仍然无法正常工作。

private void btncheckPassword_Click(object sender, EventArgs e)
    {
        bool isMatch = false;
        if(txtPlainPasswordCheck.TextLength > 0 && txtHashedPasswordCheck.TextLength > 0)
        {
            try
            {
              var Task_VerifyPassword = Task.Factory.StartNew(() => BCrypt.Net.BCrypt.Verify((String)txtPlainPasswordCheck.Text, (String)txtHashedPasswordCheck.Text));
               Task_VerifyPassword.ContinueWith(t => { throw new BCrypt.Net.SaltParseException(); }, TaskContinuationOptions.OnlyOnFaulted);
                SetCursor(Cursors.WaitCursor);
                isMatch = Task_VerifyPassword.Result;
            }
            catch (BCrypt.Net.SaltParseException e2)
            {
                SetCheckLabel(e2.Message.ToString(), Color.Red, Color.Black);

            }
            if (isMatch)
            {
                SetCheckLabel("Passwords Match", Color.Black, Color.Green);
                SetCursor(Cursors.Default);
            }
            else
            {
                SetCheckLabel("Passwords Don't Match", Color.Red, Color.Black);
                SetCursor(Cursors.Default);
            }
        }
    }

Exception is unhandled because it is thrown in one thread (thread pool thread, on which ContinueWith runs) but you are catching it on another (GUI thread). 无法处理异常,因为异常是在一个线程(运行ContinueWith线程池线程)中引发的,但是您在另一个线程(GUI线程)中捕获了异常。

I would strongly suggest to use all the benefits of async-await idiom which comes with .NET 4.5 (or .NET 4 with Microsoft.Bcl.Async package). 我强烈建议使用.NET 4.5(或带有Microsoft.Bcl.Async包的.NET 4)附带的async-await惯用法的所有优点。 With it, handling exceptions thrown from asynchronous methods comes as very natural and also continuation (code after await ) gets executed on the captured SynchronisationContext. 有了它,处理从异步方法抛出的异常就变得非常自然,并且在捕获的SynchronisationContext上也执行了继续(代码在await之后)。 You could write something like this: 您可以这样写:

private async void btncheckPassword_Click(object sender, EventArgs e)
{
    if(txtPlainPasswordCheck.TextLength > 0 &&   txtHashedPasswordCheck.TextLength > 0)
    {
        bool isMatch = false;
        SetCursor(Cursors.WaitCursor);

        try
        {
           isMatch = await Task.Run(
              () => 
              {  
                 try
                 {
                    return BCrypt.Net.BCrypt.Verify(
                       (String)txtPlainPasswordCheck.Text,                    
                       (String)txtHashedPasswordCheck.Text)
                    );
                 }
                 catch
                 {
                    throw new BCrypt.Net.SaltParseException(); 
                 }
              }
           ); 

           if (isMatch)
           {
               SetCheckLabel("Passwords Match", Color.Black, Color.Green);
           }
           else
           {
              SetCheckLabel("Passwords Don't Match", Color.Red, Color.Black);    
           }
        }
        catch (BCrypt.Net.SaltParseException e2)
        {
            SetCheckLabel(e2.Message.ToString(), Color.Red, Color.Black);
        }

        SetCursor(Cursors.Default);
    }
}

NOTE: I am not familiar with BCrypt library but it does not sound like a good idea to catch any exception from Verify and then throw BCrypt.Net.SaltParseException (you even said that this exception is thrown 'by package' but you are actually throwing it yourself). 注意:我不熟悉BCrypt库,但是从Verify捕获任何异常然后抛出BCrypt.Net.SaltParseException听起来不是一个好主意(您甚至说此异常是“按包”抛出的,但实际上是在抛出它自己)。 It would be better to allow propagation of any exception: 允许传播任何异常会更好:

isMatch = await Task.Run(
   () => 
   {  
      return BCrypt.Net.BCrypt.Verify(
         (String)txtPlainPasswordCheck.Text,                    
         (String)txtHashedPasswordCheck.Text)
      );
   }
); 

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM