开发者

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

Thanks


It is typically best to let the exception propogate up to the UI and then report the problem to the user. 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. 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. 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. 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; to rethrow the original exception (which can only happen in the catch block, not at the end of the method.

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.

Note that if the method had no return value (void), then the reachability concerns vanish, but not the logical concerns. 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? 
}
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜