简体   繁体   English

当用户输入凭据时,如何出现由凭据弹出窗口引起的异常,如何继续执行catch块?

[英]How can I continue execution of a catch block when the user enters credentials, from an exception caused by a credentials popup appears?

I made a Winforms application, which acccesses folders on another server (in another active directory domain). 我制作了一个Winforms应用程序,该应用程序访问另一个服务器(在另一个活动目录域中)上的文件夹。 The line of gets all directories from a folder, but it may sometimes fail with an exception because the credentials to access the folder (basic authentication) have not been saved, so the basic auth dialog box pops up again and again, breaking the system. 从文件夹中获取所有目录的行,但有时可能会失败,因为未保存访问文件夹的凭据(基本身份验证),因此基本身份验证对话框一次又一次弹出,从而破坏了系统。

In the corresponding catch block, how could I handle this by resuming execution of the catch block after the user enters his or her credentials and then retry the corresponding code? 在相应的catch块中,在用户输入其凭据然后重试相应的代码之后,如何通过恢复catch块的执行来处理该问题?

Thanks 谢谢

It is typically best to let the exception propogate up to the UI and then report the problem to the user. 通常最好让异常传播到UI,然后将问题报告给用户。 The user can then decide to retry the operation. 然后,用户可以决定重试该操作。 This assumes, of course, that the state of the system can be restored. 当然,这假定可以还原系统的状态。 If it is possible to code the operation in such a way that the state of the system can be restored, then that is best, because then the operation will be robust in the presence of other exceptions as well. 如果可以以可以恢复系统状态的方式对操作进行编码,那将是最好的,因为这样,在存在其他异常的情况下,该操作也会很健壮。

If the retry must continue from the point of the exception, then your best bet is probably to put that step within a loop, like this: 如果重试必须从异常的角度继续进行,那么最好的选择可能是将该步骤放在一个循环中,如下所示:

private const int maxRetryAttempts = 3;

private static MyData ReadDataFile(string path)
{
    int remainingAttempts = maxRetryAttempts;
    while (true)
    {
        try
        {
            return ReadDataFileCore(path);
        }
        catch(UnauthorizedAccessException ex)
        {
             if (remainingAttemtps <= 0)
                 throw;
             remainingAttempts--;             
             MessageBox.Show(ex.Message);
        }
    }
}

Reason for while(true) 一会儿的原因(正确)

The while(true){...} statement may look a little odd, but in this case it is necessary. while(true){...}语句可能看起来有些奇怪,但是在这种情况下是必须的。 It is not, as it appears, an infinite loop, since the method will either return a value or throw an exception within the specified number of iterations. 它不是一个无限循环,因为该方法将在指定的迭代次数内返回值或引发异常。

Normally, you would expect a loop with a non-constant controlling expression. 通常,您会期望一个带有非恒定控制表达式的循环。

private static MyData ReadDataFile(string path)
{
    int remainingAttempts = maxRetryAttempts;
    while(remainingAttempts > 0)  //  Non-constant expression.
    {
        ...
    }
}  //  Compile error - Not all code paths return a value.

This was not done in this method in order to satisfy the compiler's reachability detector. 为了满足编译器的可达性检测器,未在此方法中执行此操作。 The compiler will see the constant true in while statement and know that the statement after the while is not reachable and, therefore, the end of the method is not reachable. 编译器将在while语句中看到常量true,并且知道while之后的语句不可访问,因此,方法的末尾不可访问。 If a non-constant were chosen, then code would have to be placed after the loop to either return a value or throw an exception. 如果选择了非常量,则必须在循环后放置代码以返回值或引发异常。 Let's consider each of the options. 让我们考虑每个选项。

private static MyData ReadDataFile(string path)
{
    int remainingAttempts = maxRetryAttempts;
    while(remainingAttempts > 0)
    {
        ...
    }
    return null;
}  

We could return a null value (or some other error indicator), in which case the calling code would have to expect null values and handle them. 我们可以返回一个空值(或其他错误指示​​符),在这种情况下,调用代码将必须期望空值并对其进行处理。 This seemed like a clunky design to me. 在我看来,这似乎是一个笨拙的设计。 I would rather be guaranteed that, if the method returns, then it returns a good value. 我宁愿保证,如果该方法返回,那么它将返回一个好的值。

private static MyData ReadDataFile(string path)
{
    int remainingAttempts = maxRetryAttempts;
    while(remainingAttempts > 0)
    {
        ...
    }
    throw new UnauthroizedAccessException();  // This exception does not contain any good debugging data.
}  

The other alternative is to throw an exception at the end of the method. 另一种选择是在方法末尾引发异常。 This is a reasonable option, but it is not ideal. 这是一个合理的选择,但不是理想的选择。 If we create a new exception, then it would almost certainly be less meaningful than the one that caused the problem in the first place, which was already caught and discarded. 如果我们创建一个新的异常,那么它几乎肯定比起最初导致问题的问题(已经被捕获并丢弃)的意义要小。

Suppose we save the original exception. 假设我们保存原始异常。

private static MyData ReadDataFile(string path)
{
    UnauthorizedAccessException exception = null;
    for (int attemptCount = 0; attemptCount < maxRetryAttempts; attemptCount++)
    {
        try
        {
            return ReadDataFileCore(path);
        }
        catch(UnauthorizedAccessException ex)
        {
             exception = ex;
             MessageBox.Show(ex.Message);
        }
    }
    throw exception;  // The StackTrace gets replaced to indicate this line of code.
}

We could rethrow the exception that we caught by creating an Exception variable at the top of the method and storing the caught exception in it. 我们可以通过在方法顶部创建一个Exception变量并将捕获的异常存储在其中来重新抛出捕获的异常。 The problem with this is it will cause the stack trace to be replaced and make it harder to debug the application in the future. 这样做的问题是它将导致堆栈跟踪被替换,并且将来使调试该应用程序变得更加困难。 It is best to just let the exception propogate up unchanged by using throw; 最好通过使用throw;来让异常保持不变throw; to rethrow the original exception (which can only happen in the catch block, not at the end of the method. 重新抛出原始异常(只能在catch块中发生,而不能在方法末尾发生)。

So of all the alternatives available, I judged while(true) to be the best option, because it guarantees that control will leave this method either with good data or an uncorrupted exception. 因此,在所有可用的替代方法中,我认为while(true)是最佳选择,因为它可以确保控件将为该方法保留良好的数据或未损坏的异常。

Note that if the method had no return value ( void ), then the reachability concerns vanish, but not the logical concerns. 请注意,如果该方法没有返回值( void ),那么可达性问题就消失了,但逻辑上就没有了。 We would still have to deal with the issue of the method exiting without having performed what it was supposed to do. 我们仍然必须处理方法退出的问题,而不必执行应做的事情。

private static void ReadDataFile(string path)
{
    for (int attemptCount = 0; attemptCount < maxRetryAttempts; attemptCount++)
    {
        try
        {
            ReadDataFileCore(path);
        }
        catch(UnauthorizedAccessException ex)
        {
             MessageBox.Show(ex.Message);
        }
    }
    //  Compiles justs fine, but did we actually read the data file? 
}

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

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