Страница пользовательских ошибок ASP.NET - Server.GetLastError () имеет значение null - PullRequest
110 голосов
/ 05 декабря 2008

У меня настроена страница ошибки для моего приложения:

<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 () является нулевым

Можно ли как-нибудь получить информацию об исключении на странице ошибок, а не в Global.asax.cs?

ASP.NET 3.5 в Vista / IIS7

Ответы [ 10 ]

136 голосов
/ 05 декабря 2008

Если присмотреться к моему настройке web.config, один из комментариев в этот пост очень полезен

в asp.net 3.5 sp1 появился новый параметр redirectMode

Таким образом, мы можем изменить customErrors, чтобы добавить этот параметр:

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

режим ResponseRewrite позволяет нам загружать «страницу ошибок» без перенаправления браузера, поэтому URL остается неизменным, и, что важно для меня, информация об исключениях не теряется.

36 голосов
/ 05 декабря 2008

ОК, я нашел этот пост: http://msdn.microsoft.com/en-us/library/aa479319.aspx

с этой очень иллюстративной диаграммой:

диаграмма http://i.msdn.microsoft.com/Aa479319.customerrors_01(en-us,MSDN.10).gif

по сути, чтобы получить эти подробности об исключениях, мне нужно хранить их самостоятельно в Global.asax для последующего поиска на моей пользовательской странице ошибок.

кажется, что лучший способ - выполнить большую часть работы в Global.asax, с пользовательскими страницами ошибок, обрабатывающими полезный контент, а не логику.

19 голосов
/ 05 декабря 2008

Сочетание того, что сказал NailItDown и Виктор. Предпочтительный / самый простой способ - использовать ваш 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>

И, наконец, делайте все, что вам нужно, за исключением того, что вы сохранили на своей странице error :

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 ...
}
6 голосов
/ 23 апреля 2009

Попробуйте использовать что-то вроде Server.Transfer("~/ErrorPage.aspx"); из Application_Error() метода global.asax.cs

Тогда из Page_Load() файла ErrorPage.aspx.cs вы можете сделать что-то вроде: Exception exception = Server.GetLastError().GetBaseException();

Server.Transfer(), кажется, держит исключение вокруг.

5 голосов
/ 28 сентября 2011

Вот мое решение ..

В 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;
        }
    }
5 голосов
/ 08 июня 2011

Хотя здесь есть несколько хороших ответов, я должен отметить, что не рекомендуется выводить сообщения об исключениях системы на страницах ошибок (что, я полагаю, вы хотите сделать). Вы можете непреднамеренно сообщать злоумышленникам о том, что вы не хотите делать. Например, сообщения об исключениях Sql Server очень многословны и могут содержать имя пользователя, пароль и информацию о схеме базы данных при возникновении ошибки. Эта информация не должна отображаться конечному пользователю.

4 голосов
/ 06 июня 2010

Одним из важных соображений, которое, я думаю, всем здесь не хватает, является сценарий балансировки нагрузки (веб-фермы). Поскольку сервер, на котором выполняется global.asax, может отличаться от сервера, на котором выполняется страница пользовательской ошибки, сохранение объекта исключения в приложении ненадежно.

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

P.S. Хранить данные в коллекции приложений небезопасно, не заблокировав, а затем разблокировав.

2 голосов
/ 22 января 2017

Это сработало для меня. в 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 open page Whithout Error



И если возникает ошибка error occurs

Как и вместо отображения ошибок, переменная 'log' будет храниться в базе данных


Источник: Microsoft ASP.Net

2 голосов
/ 15 декабря 2016

Это относится к этим двум темам ниже, я хочу получить как GetHtmlErrorMessage, так и Session on Error page.

Сессия является нулевой после 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
         }
    }

Тогда 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

1 голос
/ 05 декабря 2008

Я думаю, у вас есть несколько вариантов здесь.

вы можете сохранить последнее исключение в сеансе и получить его со своей пользовательской страницы ошибок; или вы можете просто перенаправить на свою страницу ошибки в событии Application_error. Если вы выберете последний вариант, убедитесь, что вы используете метод Server.Transfer.

...