Страница пользовательской ошибки 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
с этой очень иллюстративной диаграммой:
(источник: 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.