c# Por que Response.Redirect faz com que System.Threading.ThreadAbortException?




asp.net .net-3.5 (8)

Eu até tentei evitar isso, apenas no caso de fazer o abort no thread manualmente, mas eu prefiro deixá-lo com o "CompleteRequest" e seguir em frente - meu código tem comandos de retorno após redirecionamentos de qualquer maneira. Então isso pode ser feito

public static void Redirect(string VPathRedirect, global::System.Web.UI.Page Sender)
{
    Sender.Response.Redirect(VPathRedirect, false);
    global::System.Web.UI.HttpContext.Current.ApplicationInstance.CompleteRequest();
}

Quando eu uso Response.Redirect (...) para redirecionar meu formulário para uma nova página, recebo o erro:

Uma primeira chance exceção do tipo 'System.Threading.ThreadAbortException' ocorreu em mscorlib.dll
Uma exceção do tipo 'System.Threading.ThreadAbortException' ocorreu em mscorlib.dll, mas não foi tratada no código do usuário

Meu entendimento disso é que o erro está sendo causado pelo servidor da web abortando o restante da página em que o response.redirect foi chamado.

Eu sei que posso adicionar um segundo parâmetro para Response.Redirect que é chamado endResponse. Se eu definir endResponse como True, ainda recebo o erro, mas se eu configurá-lo como False, não recebo o erro. Tenho certeza de que isso significa que o servidor está executando o restante da página da qual eu redirecionei. O que parece ser ineficiente para dizer o mínimo. Existe uma maneira melhor de fazer isso? Algo diferente de Response.Redirect ou existe uma maneira de forçar a página antiga a parar de carregar onde não receberei uma ThreadAbortException ?


O padrão correto é chamar a sobrecarga Redirect com endResponse = false e fazer uma chamada para informar ao pipeline do IIS que deve avançar diretamente para o estágio EndRequest quando você retornar o controle:

Response.Redirect(url, false);
Context.ApplicationInstance.CompleteRequest();

Esta postagem de blog de Thomas Marquardt fornece detalhes adicionais, incluindo como lidar com o caso especial de redirecionamento dentro de um manipulador Application_Error.


O que eu faço é pegar essa exceção, junto com outras possíveis exceções. Espero que isso ajude alguém.

 catch (ThreadAbortException ex1)
 {
    writeToLog(ex1.Message);
 }
 catch(Exception ex)
 {
     writeToLog(ex.Message);
 }

É assim que o Response.Redirect (url, true) funciona. Ele lança o ThreadAbortException para anular o segmento. Apenas ignore essa exceção. (Eu presumo que é algum manipulador de erro global / logger onde você o vê?)

Uma interessante discussão relacionada É Response.End () considerado prejudicial?


Eu sei que estou atrasado, mas eu só tive esse erro se meu Response.Redirect está em um bloco Try...Catch .

Nunca coloque um Response.Redirect em um bloco Try ... Catch. É má prática

Editar

Em resposta ao comentário do @ Kiquenet, aqui está o que eu faria como uma alternativa para colocar o Response.Redirect no bloco Try ... Catch.

Eu dividiria o método / função em duas etapas.

O primeiro passo dentro do bloco Try ... Catch executa as ações solicitadas e define um valor de "resultado" para indicar o sucesso ou a falha das ações.

O segundo passo fora do bloco Try ... Catch faz o redirecionamento (ou não) dependendo do valor do "resultado".

Este código está longe de ser perfeito e provavelmente não deve ser copiado já que eu não testei

public void btnLogin_Click(UserLoginViewModel model)
{
    bool ValidLogin = false; // this is our "result value"
    try
    {
        using (Context Db = new Context)
        {
            User User = new User();

            if (String.IsNullOrEmpty(model.EmailAddress))
                ValidLogin = false; // no email address was entered
            else
                User = Db.FirstOrDefault(x => x.EmailAddress == model.EmailAddress);

            if (User != null && User.PasswordHash == Hashing.CreateHash(model.Password))
                ValidLogin = true; // login succeeded
        }
    }
    catch (Exception ex)
    {
        throw ex; // something went wrong so throw an error
    }

    if (ValidLogin)
    {
        GenerateCookie(User);
        Response.Redirect("~/Members/Default.aspx");
    }
    else
    {
        // do something to indicate that the login failed.
    }
}

Eu também tive esse problema. Tente usar o Server.Transfer em vez de Response.Redirect Trabalhado para mim


Não há nenhuma solução simples e elegante para o problema de Redirect em ASP.Net WebForms. Você pode escolher entre a solução Dirty e a solução Tedious

Dirty : Response.Redirect(url) envia um redirecionamento para o navegador e, em seguida, lança um ThreadAbortedException para finalizar o segmento atual. Portanto, nenhum código é executado após a chamada Redirect (). Desvantagens: É uma má prática e tem implicações de desempenho para matar tópicos como este. Além disso, ThreadAbortedExceptions será exibido no log de exceções.

Tedious : A maneira recomendada é chamar Response.Redirect(url, false) e Context.ApplicationInstance.CompleteRequest() Entretanto, a execução do código continuará e o restante dos manipuladores de eventos no ciclo de vida da página ainda será executado. (Por exemplo, se você executar o redirecionamento em Page_Load, não somente o resto do manipulador será executado, Page_PreRender e assim por diante também será chamado - a página renderizada simplesmente não será enviada para o navegador. Você pode evitar o processamento extra por exemplo, definir um sinalizador na página e permitir que os manipuladores de eventos subsequentes verifiquem esse sinalizador antes de fazer qualquer processamento.

(A documentação para CompleteRequest declara que " Faz com que o ASP.NET ignore todos os eventos e filtragem na cadeia de execução do pipeline HTTP ". Isso pode ser facilmente mal interpretado. Ele ignora filtros e módulos HTTP adicionais, mas não ignora eventos no ciclo de vida da página atual.)

O problema mais profundo é que o WebForms não possui um nível de abstração. Quando você está em um manipulador de eventos, já está no processo de construir uma página para saída. Redirecionar em um manipulador de eventos é feio porque você está finalizando uma página parcialmente gerada para gerar uma página diferente. O MVC não tem esse problema, pois o fluxo de controle é separado das visualizações de renderização, portanto, é possível fazer um redirecionamento limpo simplesmente retornando uma RedirectAction no controlador, sem gerar uma visualização.


Aqui está a linha oficial sobre o problema (não consegui encontrar o mais recente, mas não acho que a situação tenha mudado para versões posteriores do .net)





.net-3.5