Страница пользовательской ошибки ASP.NET - Server.GetLastError() - null

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

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

ASP.NET 3.5 в Vista/IIS7

Ответ 1

Более внимательно рассмотрев мой setup.config, один из комментариев в этот пост очень полезен

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

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

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

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

Ответ 2

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

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

diagram
(источник: microsoft.com)

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

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

Ответ 3

Комбинация того, что сказал 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>

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

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

Ответ 4

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

Затем изнутри Page_Load() от ErrorPage.aspx.cs вы должны быть в порядке, чтобы сделать что-то вроде: Exception exception = Server.GetLastError().GetBaseException();

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

Ответ 5

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

Ответ 6

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

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

Ответ 7

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

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

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

Ответ 8

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

Сессия null после ResponseRewrite

Почему HttpContext.Session null, когда 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

Ответ 9

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



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

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


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

Ответ 10

Думаю, у вас есть пара вариантов.

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