简体   繁体   中英

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. 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.

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. 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. I tried adding a saltParaseException handling but it still won't work.

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).

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). With it, handling exceptions thrown from asynchronous methods comes as very natural and also continuation (code after await ) gets executed on the captured SynchronisationContext. 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). 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)
      );
   }
); 

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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