ASP.NET 사용자 지정 오류 페이지-Server.GetLastError ()가 null입니다.


112

내 응용 프로그램에 대해 사용자 지정 오류 페이지가 설정되어 있습니다.

<customErrors mode="On" defaultRedirect="~/errors/GeneralError.aspx"
/>

Global.asax, Application_Error ()에서 다음 코드는 예외 세부 정보를 가져 오기 위해 작동합니다.

  Exception ex = Server.GetLastError();
  if (ex != null)
    {
        if (ex.GetBaseException() != null)
            ex = ex.GetBaseException();
    }

내 오류 페이지 (~ / errors / GeneralError.aspx.cs)에 도달 할 때까지 Server.GetLastError ()는 null입니다.

Global.asax.cs가 아닌 오류 페이지에서 예외 세부 정보를 얻을 수있는 방법이 있습니까?

Vista / IIS7의 ASP.NET 3.5


Cassini를 사용하는 Win7의 ASP.NET 4.0에도 적용
Marcel

추가 "<customErrors에 모드 ="RemoteOnly "defaultRedirect에 ="~ / 오류 / GeneralError.aspx "redirectMode ="ResponseRewrite "/>"확인 답변으로
elle0087

답변:


137

내 web.config 설정을 자세히 살펴보면 이 게시물 의 의견 중 하나 가 매우 유용합니다.

asp.net 3.5 sp1에는 새로운 매개 변수 redirectMode가 있습니다.

따라서이 customErrors매개 변수를 추가 하도록 수정할 수 있습니다.

<customErrors mode="RemoteOnly" defaultRedirect="~/errors/GeneralError.aspx" redirectMode="ResponseRewrite" />

ResponseRewrite모드를 사용하면 브라우저를 리디렉션하지 않고«오류 페이지»를로드 할 수 있으므로 URL은 동일하게 유지되며 중요한 것은 예외 정보가 손실되지 않는다는 것입니다.


4
이것은 나를 위해 작동하지 않았습니다. 예외 정보가 손실됩니다. Application_Error ()의 세션에 저장하고 오류 페이지의 Page_Load () 처리기에서 다시 가져옵니다.
BrianK 2009-08-07

2
그것은 모든 문서에서 표준이되어야합니다. 이건 너무 좋아서 더 이상 이전 행동을 지원할 이유가 없다고 생각합니다. 상태 코드가 정확하면 원래 요청 URL을 그대로 두는 데 문제가 없어야합니다 (브라우저 리디렉션을 수행하지 않음). 실제로 응답 코드는 공유 오류 페이지 요청이 아닌 요청 된 URL과 관련되기 때문에 HTTP에 따라 더 정확합니다. 새로운 기능을 놓친 포인터에 감사드립니다!
Tony Wall

UpdatePanels 내부 의 컨트롤에 의해 트리거 된 예외에서는 작동하지 않습니다 . 오류 페이지가 더 이상 표시되지 않습니다.
Sam

2
이 좋은 것을 증명하기 위해 내 댓글을 추가하는 이전 답변 이후 redirectmode의 ResponseRewrite 값이 Asp.Net 4.5에서 작동합니다
Sundara Prabu

38

좋아요,이 게시물을 찾았습니다 : http://msdn.microsoft.com/en-us/library/aa479319.aspx

이 매우 예시적인 다이어그램으로 :

도표
(출처 : microsoft.com )

본질적으로 이러한 예외 세부 정보를 얻으려면 나중에 사용자 지정 오류 페이지에서 검색 할 수 있도록 Global.asax에 직접 저장해야합니다.

가장 좋은 방법은 Global.asax에서 대부분의 작업을 수행하는 것 같습니다. 사용자 지정 오류 페이지는 논리가 아닌 유용한 콘텐츠를 처리합니다.


18

NailItDown과 Victor가 말한 것의 조합. 선호하는 / 가장 쉬운 방법은 Global.Asax를 사용하여 오류를 저장 한 다음 사용자 지정 오류 페이지로 리디렉션하는 것입니다.

Global.asax :

    void Application_Error(object sender, EventArgs e) 
{
    // Code that runs when an unhandled error occurs
    Exception ex = Server.GetLastError();
    Application["TheException"] = ex; //store the error for later
    Server.ClearError(); //clear the error so we can continue onwards
    Response.Redirect("~/myErrorPage.aspx"); //direct user to error page
}

또한 web.config 를 설정해야합니다 .

  <system.web>
    <customErrors mode="RemoteOnly" defaultRedirect="~/myErrorPage.aspx">
    </customErrors>
  </system.web>

마지막으로 오류 페이지에 저장 한 예외를 제외하고 필요한 모든 작업을 수행 합니다 .

protected void Page_Load(object sender, EventArgs e)
{

    // ... do stuff ...
    //we caught an exception in our Global.asax, do stuff with it.
    Exception caughtException = (Exception)Application["TheException"];
    //... do stuff ...
}

35
응용 프로그램에 저장하면 시스템의 다른 모든 사용자는 어떻습니까? 세션에 있어야하지 않습니까?
BrianK

11
실제로 이것은 Application [ "TheException"]에 저장하는 것은 정말 나쁜 접근 방식입니다.
Junior Mayhé 2010-07-07

4
또한 사용자 당 여러 "탭"을 지원하려는 경우 예외에 세션 저장소의 고유 키를 제공 한 다음 오류 페이지로 리디렉션 할 때 해당 키를 쿼리 문자열 매개 변수로 포함 할 수 있습니다.
Anders Fjeldstad 2011

5
+1하지만 Application[]이것이 전역 개체 라는 점에 유의하십시오 . 이론적으로 두 번째 페이지가 오류를 덮어 쓰는 경쟁 조건이있을 수 있습니다. 그러나 Session[]오류 조건에서 항상 사용할 수있는 것은 아니기 때문에 이것이 더 나은 선택이라고 생각합니다.
Andomar 2013 년

3
예외를 저장하는 데 사용되는 키에 새 GUID 접두사를 추가하고 GUID를 매개 변수로 사용자 지정 오류 페이지에 전달하면됩니다.
SteveGSD

6

Server.Transfer("~/ErrorPage.aspx");내부에서 와 같은 것을 사용해보십시오 .Application_Error()global.asax.cs 메서드

그런 다음 Page_Load()ErrorPage.aspx.cs 내에서 다음 과 같은 작업을 수행해도됩니다.Exception exception = Server.GetLastError().GetBaseException();

Server.Transfer() 예외가 계속되는 것 같습니다.


이것이 내 응용 프로그램이 수행 한 방법이며 99 %의 오류에 대해 꽤 잘 작동했습니다. 그러나 오늘 렌더링 단계에서 발생하는 예외를 발견했습니다. 당신이 경우 Server.Transfer페이지 후 반 렌더링입니다, 다음 페이지의 HTML 당신은 단순히 이미 렌더링 된 무엇에 연결됩니다을 전송합니다. 따라서 절반의 깨진 페이지와 그 아래에 오류 페이지가 나타날 수 있습니다.
Kevin

어떤 이유로 Server.Transfer ()를 호출하면 문제가 발생하고 오류가 전혀 표시되지 않습니다. 따라서이 방법을 사용하지 않는 것이 좋습니다. 위에서 제안한대로 web.config 줄을 사용하기 만하면 (<customErrors mode = "RemoteOnly"defaultRedirect = "~ / errors / GeneralError.aspx"redirectMode = "ResponseRewrite"/>) 제대로 작동합니다
Naresh Mittal

5

여기에 몇 가지 좋은 답변이 있지만 오류 페이지에 시스템 예외 메시지를 표시하는 것은 좋지 않다는 점을 지적해야합니다 (이는 사용자가 원하는 작업입니다). 원하지 않는 것을 악의적 인 사용자에게 실수로 공개 할 수 있습니다. 예를 들어 Sql Server 예외 메시지는 매우 장황하며 오류 발생시 데이터베이스의 사용자 이름, 암호 및 스키마 정보를 제공 할 수 있습니다. 해당 정보는 최종 사용자에게 표시되지 않아야합니다.


1
제 경우에는 백엔드 사용을위한 예외 정보 만 원했지만 좋은 조언입니다.
nailitdown

2
질문에 대답하지 않습니다.
Arne Evertsson 2015 년

5

여기 내 해결책이 있습니다 ..

Global.aspx에서 :

void Application_Error(object sender, EventArgs e)
    {
        // Code that runs when an unhandled error occurs

        //direct user to error page 
        Server.Transfer("~/ErrorPages/Oops.aspx"); 
    }

Oops.aspx에서 :

protected void Page_Load(object sender, EventArgs e)
    {
        if (!IsPostBack)
            LoadError(Server.GetLastError()); 
    }

    protected void LoadError(Exception objError)
    {
        if (objError != null)
        {
            StringBuilder lasterror = new StringBuilder();

            if (objError.Message != null)
            {
                lasterror.AppendLine("Message:");
                lasterror.AppendLine(objError.Message);
                lasterror.AppendLine();
            }

            if (objError.InnerException != null)
            {
                lasterror.AppendLine("InnerException:");
                lasterror.AppendLine(objError.InnerException.ToString());
                lasterror.AppendLine();
            }

            if (objError.Source != null)
            {
                lasterror.AppendLine("Source:");
                lasterror.AppendLine(objError.Source);
                lasterror.AppendLine();
            }

            if (objError.StackTrace != null)
            {
                lasterror.AppendLine("StackTrace:");
                lasterror.AppendLine(objError.StackTrace);
                lasterror.AppendLine();
            }

            ViewState.Add("LastError", lasterror.ToString());
        }
    }

   protected void btnReportError_Click(object sender, EventArgs e)
    {
        SendEmail();
    }

    public void SendEmail()
    {
        try
        {
            MailMessage msg = new MailMessage("webteam", "webteam");
            StringBuilder body = new StringBuilder();

            body.AppendLine("An unexcepted error has occurred.");
            body.AppendLine();

            body.AppendLine(ViewState["LastError"].ToString());

            msg.Subject = "Error";
            msg.Body = body.ToString();
            msg.IsBodyHtml = false;

            SmtpClient smtp = new SmtpClient("exchangeserver");
            smtp.Send(msg);
        }

        catch (Exception ex)
        {
            lblException.Text = ex.Message;
        }
    }

4

여기에서 모두가 놓치고 있다고 생각하는 한 가지 중요한 고려 사항은로드 밸런싱 (웹 팜) 시나리오입니다. global.asax를 실행하는 서버는 사용자 지정 오류 페이지를 실행하는 서버와 다를 수 있으므로 Application에 예외 개체를 숨기는 것은 신뢰할 수 없습니다.

나는 여전히 웹 팜 구성 에서이 문제에 대한 신뢰할 수있는 솔루션을 찾고 있으며, 사용자 지정 오류 페이지에서 Server.GetLastError로 예외를 선택할 수없는 이유에 대한 MS의 좋은 설명을 찾고 있습니다. global.asax Application_Error에서.

PS 데이터를 먼저 잠근 다음 잠금 해제하지 않고 응용 프로그램 컬렉션에 데이터를 저장하는 것은 안전하지 않습니다.


이것은 클라이언트 측 리디렉션을 수행하는 경우에만 해당됩니다. 서버 전송을 수행 할 때는 모두 하나의 요청의 일부이므로 application_error-> page_load는 모두 팜의 한 서버에서 순서대로 발생합니다.
davewasthere

2

이것은 아래의 두 주제와 관련이 있으므로 GetHtmlErrorMessage 및 오류 페이지 세션을 모두 가져오고 싶습니다.

ResponseRewrite 후 세션이 null입니다.

redirectMode = ResponseRewrite 일 때 HttpContext.Session이 null 인 이유

나는 필요하지 않은 해결책을 시도하고 보았습니다. Server.Transfer() or Response.Redirect()

첫째 : web.config에서 ResponseRewrite 제거

Web.config

<customErrors defaultRedirect="errorHandler.aspx" mode="On" />

그런 다음 Global.asax

    void Application_Error(object sender, EventArgs e)
    {
         if(Context.IsCustomErrorEnabled)
         {     
            Exception ex = Server.GetLastError();
            Application["TheException"] = ex; //store the error for later
         }
    }

그런 다음 errorHandler.aspx.cs

        protected void Page_Load(object sender, EventArgs e)
            {       
                string htmlErrorMessage = string.Empty ;
                Exception ex = (Exception)Application["TheException"];
                string yourSessionValue = HttpContext.Current.Session["YourSessionId"].ToString();

                //continue with ex to get htmlErrorMessage 
                if(ex.GetHtmlErrorMessage() != null){              
                    htmlErrorMessage = ex.GetHtmlErrorMessage();
                }   
                // continue your code
            }

참조 용

http://www.developer.com/net/asp/article.php/3299641/ServerTransfer-Vs-ResponseRedirect.htm


2

그것은 나를 위해 일했습니다. MVC 5에서


~\Global.asax

void Application_Error(object sender, EventArgs e)
{
    FTools.LogException();
    Response.Redirect("/Error");
}


에서 ~\Controllers만들기ErrorController.cs

using System.Web.Mvc;

namespace MVC_WebApp.Controllers
{
    public class ErrorController : Controller
    {
        // GET: Error
        public ActionResult Index()
        {
            return View("Error");
        }
    }
}


에서 ~\Models만들기FunctionTools.cs

using System;
using System.Web;

namespace MVC_WebApp.Models
{
    public static class FTools
    {
        private static string _error;
        private static bool _isError;

        public static string GetLastError
        {
            get
            {
                string cashe = _error;
                HttpContext.Current.Server.ClearError();
                _error = null;
                _isError = false;
                return cashe;
            }
        }
        public static bool ThereIsError => _isError;

        public static void LogException()
        {
            Exception exc = HttpContext.Current.Server.GetLastError();
            if (exc == null) return;
            string errLog = "";
            errLog += "**********" + DateTime.Now + "**********\n";
            if (exc.InnerException != null)
            {
                errLog += "Inner Exception Type: ";
                errLog += exc.InnerException.GetType() + "\n";
                errLog += "Inner Exception: ";
                errLog += exc.InnerException.Message + "\n";
                errLog += "Inner Source: ";
                errLog += exc.InnerException.Source + "\n";
                if (exc.InnerException.StackTrace != null)
                {
                    errLog += "\nInner Stack Trace: " + "\n";
                    errLog += exc.InnerException.StackTrace + "\n";
                }
            }
            errLog += "Exception Type: ";
            errLog += exc.GetType().ToString() + "\n";
            errLog += "Exception: " + exc.Message + "\n";
            errLog += "\nStack Trace: " + "\n";
            if (exc.StackTrace != null)
            {
                errLog += exc.StackTrace + "\n";
            }
            _error = errLog;
            _isError = true;
        }
    }
}


~\Views폴더를 생성 Error 하고에 것은 ~\Views\Error만들기Error.cshtml

@using MVC_WebApp.Models
@{
    ViewBag.Title = "Error";
    if (FTools.ThereIsError == false)
    {
        if (Server.GetLastError() != null)
        {
            FTools.LogException();
        }
    }
    if (FTools.ThereIsError == false)
    {
        <br />
        <h1>No Problem!</h1>
    }
    else
    {
        string log = FTools.GetLastError;
        <div>@Html.Raw(log.Replace("\n", "<br />"))</div>
    }
}


이 주소를 입력하면 localhost/Error 페이지 열기 Whithout 오류



그리고 오류가 발생하면 오류 발생

오류를 표시하는 대신 데이터베이스에 저장 될 변수 'log'


출처 : Microsoft ASP.Net


1

여기에 몇 가지 옵션이 있다고 생각합니다.

세션에 마지막 예외를 저장하고 사용자 정의 오류 페이지에서 검색 할 수 있습니다. 또는 Application_error 이벤트 내에서 사용자 지정 오류 페이지로 리디렉션 할 수 있습니다. 후자를 선택하는 경우 Server.Transfer 메서드를 사용해야합니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.