即使发生异常,任务仍会继续执行

Task continuous execution even after exception

下面任务中的方法 RelatoriosEstaticos.AbrirDataAtual 正在返回方法本身已处理的异常,问题是任务继续执行下一个var links = ListArquivos.ListaLinksDownlaod(driver); 这取决于要执行的方法 AbrirDataAtual(),它也会抛出异常.我试图在方法内处理,将任务放在 Try / catch 中,但没有任何效果,方法 ListaLinksDownlaod 中总是存在异常,甚至不应该到达那里。

如何停止任务的执行,比如我们发送了一个CancellationToken,但是这个时候出现了异常。

private async Task<List<IWebElement>> Acessar(IWebDriver driver, string data, CancellationToken ct)
{
    return await Task.Run(() =>
    {
        ct.ThrowIfCancellationRequested();

        LoginNgin.Login(config.User, config.Password, driver);

        RelatoriosEstaticos.AbrirRelatoriosEstaticos(driver);

        RelatoriosEstaticos.AbrirDataAtual(driver, data);

        var links = ListArquivos.ListaLinksDownlaod(driver);

        MethodInvoker action = delegate { pgbStatus.Maximum = links.Count(); };
        pgbStatus.BeginInvoke(action);

        return links;
    });
}

如果没有看到 AbrirDataAtual 的实际实现,就无法确定,但看起来这个方法确实正在处理不应该在那里处理的异常。

一般来说,方法应该处理异常适当(通过适当 我的意思是它可以将应用程序恢复到程序可以安全继续的状态,通知用户有关错误等),否则它根本不应该处理它并让异常传播到方法的调用者。

根据您对问题的描述,AbrirDataAtual 没有(也不能)正确处理异常,因此您不应该在那里捕获异常(或者如果必须在那里捕获异常,你应该 re-throw 它)。将跳过以下所有方法(包括 ListArquivos.ListaLinksDownlaod),直到处理异常为止。问题已解决!

下面的例子展示了如何直接在任务中处理异常(在AbrirDataAtual中移除异常处理之后)。但它可能仍然不是此类异常处理程序的最佳位置,但同样,找到这样的位置需要完整的源代码,因此仅以它为例来阐明我在说什么:

private async Task<List<IWebElement>> Acessar(IWebDriver driver, string data, CancellationToken ct)
{
    return await Task.Run(() =>
    {
        ct.ThrowIfCancellationRequested();

        LoginNgin.Login(config.User, config.Password, driver);

        RelatoriosEstaticos.AbrirRelatoriosEstaticos(driver);

        try
        {
            RelatoriosEstaticos.AbrirDataAtual(driver, data);

            var links = ListArquivos.ListaLinksDownlaod(driver);

            MethodInvoker action = delegate { pgbStatus.Maximum = links.Count(); };
            pgbStatus.BeginInvoke(action);

            return links;
        }
        catch (Exception)//Use more specific exception type if possible
        {
            //Do all neccesary to properly handle the exception
        }
    });
}

如果您仍然认为 AbrirDataAtual 方法是处理异常的正确位置,另一种方法是将 AbrirDataAtual 修改为 return 布尔标志,指示 success/failure它的操作,例如:

bool AbrirDataAtual(IWebDriver driver, string data)
{
    try
    {
        //Do all the neccessary stuff
        ...

        //Indicate that AbrirDataAtual succeeded
        return true;
    }
    catch(Exception)
    {
        //Handle exception properly
        ...

        //Indicate that AbrirDataAtual failed
        return false;
    }
}

private async Task<List<IWebElement>> Acessar(IWebDriver driver, string data, CancellationToken ct)
{
    return await Task.Run(() =>
    {
        ct.ThrowIfCancellationRequested();

        LoginNgin.Login(config.User, config.Password, driver);

        RelatoriosEstaticos.AbrirRelatoriosEstaticos(driver);

        if (RelatoriosEstaticos.AbrirDataAtual(driver, data))
        {
            //Continue execution
            var links = ListArquivos.ListaLinksDownlaod(driver);

            MethodInvoker action = delegate { pgbStatus.Maximum = links.Count(); };
            pgbStatus.BeginInvoke(action);

            return links;
        }
        else
        {
            //AbrirDataAtual failed
            return null;
            //or throw exception if appropriate
            throw new Exception();
        }
    });
}