c# - Response.Redirect가 System.Threading.ThreadAbortException을 발생시키는 이유는 무엇입니까?




asp.net .net-3.5 (9)

Response.Redirect (...)를 사용하여 내 양식을 새 페이지로 리디렉션하면 오류가 발생합니다.

mscorlib.dll에서 'System.Threading.ThreadAbortException'유형의 첫 번째 예외가 발생했습니다.
mscorlib.dll에서 'System.Threading.ThreadAbortException'유형의 예외가 발생했지만 사용자 코드에서 처리되지 않았습니다.

이것에 대한 나의 이해는 웹 서버가 response.redirect가 호출 된 페이지의 나머지 부분을 중단함으로써 오류가 발생한다는 것입니다.

endResponse라는 Response.Redirect 두 번째 매개 변수를 추가 할 수 있다는 것을 알고 있습니다. endResponse를 True로 설정하면 여전히 오류가 발생하지만 False로 설정하면 오류가 발생합니다. 나는 웹 서버가 내가 리디렉션 된 페이지의 나머지 부분을 실행하고 있다는 것을 의미하지만 꽤 확신한다. 최소한을 말하면 비효율적 인 것처럼 보일 것입니다. 이 작업을 수행하는 더 좋은 방법이 있습니까? Response.Redirect 이외의 것이거나 이전 페이지에서 ThreadAbortException 얻지 못할 곳을 강제로로드하는 방법이 있습니까?


Answers

Response.Redirect() 는 현재 요청을 중단하는 예외를 throw합니다.

이 기술 자료 문서에서는 Request.End()Server.Transfer() 메서드에 Server.Transfer() 동작을 설명합니다.

Response.Redirect() 에는 과부하가 있습니다.

Response.Redirect(String url, bool endResponse)

endResponse = false 를 전달하면 예외가 발생하지 않지만 런타임은 현재 요청을 계속 처리합니다.

endResponse = true (또는 다른 오버로드가 사용 된 경우) 예외가 발생하고 현재 요청이 즉시 종료됩니다.


나도 그 문제가 있었다. Response.Redirect 대신 Server.Transfer를 사용해보십시오. 나를 위해 일했습니다.


ASP.Net WebForms의 Redirect 문제에 대한 간단하고 우아한 해결책은 없습니다 . Dirty 솔루션과 Tedious 솔루션 중에서 선택할 수 있습니다.

Dirty : Response.Redirect(url) 은 브라우저로 리디렉션을 보내고 ThreadAbortedException 을 throw하여 현재 스레드를 종료합니다. 따라서 코드는 Redirect () 호출을 지나서 실행되지 않습니다. 단점 :이 같은 스레드를 죽이는 것은 나쁜 습관이고 성능에 영향을 미칩니다. 또한 예외 로깅에서 ThreadAbortedExceptions 가 표시됩니다.

지루한 질문 : Response.Redirect(url, false) 를 호출 한 다음 Context.ApplicationInstance.CompleteRequest() 를 호출하는 것이 좋습니다. 그러나 코드 실행은 계속되고 페이지 수명주기의 나머지 이벤트 핸들러는 여전히 실행됩니다. 예를 들어 Page_Load에서 리디렉션을 수행하면 나머지 핸들러가 실행될뿐만 아니라 Page_PreRender 등도 호출되며 렌더링 된 페이지는 브라우저로 전송되지 않습니다. 예를 들어 페이지에 플래그를 설정 한 다음 후속 이벤트 핸들러가 처리를 수행하기 전에이 플래그를 확인하도록 할 수 있습니다.

( CompleteRequest 대한 문서에 " ASP.NET이 모든 이벤트를 우회하여 실행의 HTTP 파이프 라인 체인에서 필터링됩니다 ."이것은 쉽게 오해 될 수 있으며 추가 HTTP 필터와 모듈을 우회하지만 더 이상 무시하지 않습니다. 현재 페이지 수명주기의 이벤트

더 심각한 문제는 WebForms에 추상 수준이 없다는 것입니다. 이벤트 핸들러에 있으면 이미 출력 할 페이지를 작성하는 중입니다. 다른 페이지를 생성하기 위해 부분적으로 생성 된 페이지를 종료하기 때문에 이벤트 핸들러에서 리디렉션하는 것은 추악합니다. MVC는 컨트롤 흐름이 렌더링보기와 분리되어 있기 때문에이 문제가 발생하지 않으므로보기를 생성하지 않고 컨트롤러에서 RedirectAction 을 반환하기 만하면 깨끗한 리디렉션을 수행 할 수 있습니다.


내가 늦었다는 것을 알지만, Response.RedirectTry...Catch 블록에 있다면이 오류가 발생했을뿐입니다.

Response.Redirect를 Try ... Catch 블록에 넣지 마십시오. 나쁜 습관이다.

편집하다

@ Kiquenet의 코멘트에 대한 응답으로 Response.Redirect를 Try ... Catch 블록에 넣는 대신 할 수있는 방법이 있습니다.

방법 / 기능을 두 단계로 나눌 수 있습니다.

Try ... Catch 블록 내의 1 단계는 요청 된 동작을 수행하고 동작의 성공 또는 실패를 나타내는 "결과"값을 설정합니다.

Try ... Catch 블록 외부의 두 번째 단계는 "결과"값이 무엇인지에 따라 리디렉션을 수행합니다 (또는 수행하지 않습니다).

이 코드는 완벽하지 않으며 테스트하지 않았으므로 복사해서는 안됩니다.

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

내가하는 일은 다른 예외와 함께이 예외를 잡는 것입니다. 희망이 도움이 누군가.

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

심지어 경우에 수동으로 스레드에서 중단 작업을 피하기 위해 tryed 있지만 오히려 "CompleteRequest"함께 이동하고 이동 - 내 코드가 리디렉션 어쨌든 반환 명령이 있습니다. 이렇게 할 수 있습니다.

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();
}

이것은 Response.Redirect (url, true)가 작동하는 방법입니다. 스레드를 중단시키기 위해 ThreadAbortException을 던집니다. 그 예외를 그냥 무시하십시오. (나는 그것이 당신이 그것을 보는 몇몇 전역 에러 핸들러 / 로거라고 추정한다.)

흥미로운 관련 토론 Response.End ()가 유해한 것으로 간주됩니까?


문제의 공식 라인 은 다음과 같습니다 (최신을 찾을 수는 없지만 이후 버전의 .net에서는 상황이 변경된 것으로 생각하지 않습니다).


root 는 응용 프로그램의 모든 로그를 의미하며 logger 는 특정 종류의 로그를 참조 할 수 있습니다. 로그를 사용하면 cetain 로그에 대해서만 로그 구성을 변경할 수 있습니다. 의견이있는 샘플을보십시오.

<!-- Set root logger level to INFO-->
<root>
    <level value="INFO" />
</root>

<!-- Print only messages of level WARN or above in the package "File" -->
<logger name="File">
    <level value="WARN" />
</logger>

이 샘플에서 모든 로그는 INFO이고 "File"(또는 이름이 지정된) 유형의 로그는 WARN입니다.





c# asp.net .net-3.5