Спеціальна сторінка помилок ASP.NET - Server.GetLastError () є нульовою


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

На той момент, коли я потрапляю на свою сторінку помилок (~ / помилки / GeneralError.aspx.cs), сервер.GetLastError () є нульовим

Чи можна отримати детальну інформацію про винятки на сторінці помилок, а не на Global.asax.cs?

ASP.NET 3.5 на Vista / IIS7


Застосовується також на ASP.NET 4.0 на Win7 разом із Cassini
Marcel

додати "<customErrors mode =" 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режим дозволяє завантажити «Error Page» без перенаправлення браузера, тому в URL залишається колишнім, і , що важливо для мене, інформація про виключення не втрачається.


4
Це не спрацювало для мене. Інформація про виняток втрачається. Я б зберігав його в сеансі в Application_Error () і витягував його назад в обробник Page_Load () моєї сторінки помилок.
BrianK

2
Це має бути нормою у всій документації. Це так добре, що я не бачу причин більше підтримувати стару поведінку. Поки код статусу правильний, не повинно виникнути проблем із тим, щоб залишити оригінальну URL-адресу запиту недоторканою (не робити переспрямування браузера). Насправді, це правильніше згідно HTTP, оскільки код відповіді стосується запитуваної URL-адреси, а не спільного запиту на сторінці помилок. Дякую за вказівник, я пропустив цю нову функцію!
Tony Wall

Це не працює з винятками, викликаними елементами управління всередині UpdatePanels; сторінка помилок більше не відображатиметься
Сем

2
оскільки його стара відповідь додає мій коментар, щоб довести це приємне значення ResponseRewrite в redirectmode працює в 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
Дійсно, це дійсно поганий підхід до зберігання цього додатка ["TheException"]
Junior Mayhé

4
Крім того, якщо ви хочете підтримувати кілька "вкладок" на кожного користувача, ви можете надати винятку унікальний ключ у магазині сесій, а потім включити цей ключ як параметр запиту при перенаправлення на сторінку помилок.
Андерс Ф'єльдстад

5
+1 Але пам’ятайте, що Application[]це глобальний об’єкт. Теоретично у вас може бути умова перегонів, коли друга сторінка замінює помилку. Однак, оскільки Session[]це не завжди доступно в умовах помилок, я вважаю, що це кращий вибір.
Андомар

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 сторінки, на яку ви переходите, просто приєднується до того, що вже було надано. Таким чином, у вас може з’явитися половина зламаної сторінки, а за нею - сторінка помилок.
Кевін

Чомусь дзвінок на Server.Transfer () викликає проблеми, а помилка взагалі не відображається. Отже, я не рекомендую використовувати цей метод. Просто використовуйте рядок web.config, як було запропоновано вище (<customErrors mode = "RemoteOnly" defaultRedirect = "~ / помилки / GeneralError.aspx" redirectMode = "ResponseRewrite" />), і це прекрасно працює
Naresh Mittal

5

Незважаючи на те, що тут є кілька хороших відповідей, я мушу зазначити, що не дуже добре показувати повідомлення про виключення системи на сторінках помилок (що я припускаю, що ви хочете зробити). Ви можете ненавмисно виявити зловмисним користувачам речі, які ви не хочете робити. Наприклад, повідомлення про виключення сервера Sql є дуже багатослівними і можуть давати інформацію про ім’я користувача, пароль та схему бази даних, коли виникає помилка. Ця інформація не повинна відображатися кінцевому користувачеві.


1
У моєму випадку я хотів лише інформацію про виключення для використання в кінцевому підсумку, але це хороша порада.
nailitdown

2
Не відповідає на запитання.
Арне Евертссон

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, може відрізнятись від сервера, який стосується виконання спеціальної сторінки помилок, зберігання об’єкта виключення в програмі не є надійним.

Я все ще шукаю надійне рішення цієї проблеми в конфігурації веб-ферми та / або хороше пояснення від MS щодо того, чому ви просто не можете забрати виняток із Server.GetLastError на спеціальній сторінці помилок, як ви можете. в global.asax Application_Error.

PS Небезпечно зберігати дані в колекції додатків, попередньо не блокуючи їх, а потім розблоковуючи.


Це станеться лише в тому випадку, якщо ви робите переспрямування на стороні клієнта. Під час передачі сервера все це є частиною одного запиту, тому application_error -> page_load все відбуватиметься на одному сервері ферми, послідовно.
davewast

2

Це стосується цих двох тем нижче, я хочу отримати GetHtmlErrorMessage та сесію на сторінці помилок.

Сесія є нульовою після ResponseRewrite

Чому HttpContext.Session недійсний, коли redirectMode = ResponseRewrite

Я спробував і побачити рішення, яке не потрібно Server.Transfer() or Response.Redirect()

По-перше: видаліть ResponseRewrite в web.config

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

Потім помилкаHandler.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 відкрити сторінку без помилки



І якщо трапиться помилка трапляється помилка

Як може бути замість відображення помилок, змінна 'журнал' зберігається в базі даних


Джерело: Microsoft ASP.Net


1

Я думаю, у вас тут є пара варіантів.

ви можете зберегти останній виняток у сесії та отримати його зі своєї користувацької сторінки помилок; або ви можете просто переспрямувати на свою власну сторінку помилок у рамках події Application_error. Якщо ви виберете останнє, ви хочете переконатися, що ви використовуєте метод Server.Transfer.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.