J'ai une page d'erreur personnalisée configurée pour mon application:
<customErrors mode="On" defaultRedirect="~/errors/GeneralError.aspx"
/>
Dans Global.asax, Application_Error (), le code suivant permet d'obtenir les détails de l'exception:
Exception ex = Server.GetLastError();
if (ex != null)
{
if (ex.GetBaseException() != null)
ex = ex.GetBaseException();
}
Au moment où j'arrive à ma page d'erreur (~/errors/GeneralError.aspx.cs), Server.GetLastError () est null
Existe-t-il un moyen d'obtenir les détails de l'exception sur la page d'erreur plutôt que dans Global.asax.cs?
ASP.NET 3.5 sur Vista/IIS7
En regardant de plus près ma configuration web.config, l'un des commentaires de ce post est très utile
dans asp.net 3.5 sp1 il y a un nouveau paramètre redirectMode
Nous pouvons donc modifier customErrors
pour ajouter ce paramètre:
<customErrors mode="RemoteOnly" defaultRedirect="~/errors/GeneralError.aspx" redirectMode="ResponseRewrite" />
le mode ResponseRewrite
nous permet de charger la "page d'erreur" sans rediriger le navigateur, de sorte que l'URL reste la même et, ce qui est important pour moi, les informations sur les exceptions ne sont pas perdues.
OK, j'ai trouvé ce message: http://msdn.Microsoft.com/en-us/library/aa479319.aspx
avec ce schéma très illustratif:
(source: Microsoft.com )
en gros, pour obtenir ces détails sur les exceptions, j'ai besoin de les stocker moi-même dans Global.asax, pour pouvoir les récupérer plus tard sur ma page d'erreur personnalisée.
il semble que le meilleur moyen consiste à effectuer la majeure partie du travail dans Global.asax, les pages d'erreur personnalisées gérant du contenu utile plutôt que la logique.
Une combinaison de ce que NailItDown et Victor ont dit. La méthode préférée/la plus simple consiste à utiliser votre Global.Asax pour stocker l'erreur, puis à la rediriger vers votre page d'erreur personnalisée.
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
}
De plus, vous devez configurer votre web.config:
<system.web>
<customErrors mode="RemoteOnly" defaultRedirect="~/myErrorPage.aspx">
</customErrors>
</system.web>
Et enfin, faites ce que vous devez avec l'exception que vous avez stockée dans votre page d'erreur:
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 ...
}
Essayez d'utiliser quelque chose comme Server.Transfer("~/ErrorPage.aspx");
à partir de la méthode Application_Error()
de global.asax.cs.
Ensuite, à partir de Page_Load()
de ErrorPage.aspx.cs, vous devriez pouvoir faire quelque chose comme: Exception exception = Server.GetLastError().GetBaseException();
Server.Transfer()
semble garder l'exception à la traîne.
Voici ma solution ..
Dans 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");
}
Dans 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;
}
}
Bien qu'il y ait plusieurs bonnes réponses ici, je dois souligner que ce n'est pas une bonne pratique d'afficher les messages d'exception du système sur les pages d'erreur (c'est ce que je suppose que vous voulez faire). Vous pouvez révéler par inadvertance des choses que vous ne souhaitez pas faire à des utilisateurs malveillants. Par exemple, les messages d'exception de Sql Server sont très détaillés et peuvent donner le nom d'utilisateur, le mot de passe et les informations de schéma de la base de données en cas d'erreur. Ces informations ne doivent pas être affichées pour un utilisateur final.
Un facteur important qui, à mon avis, manque à tout le monde ici est le scénario d'équilibrage de charge (batterie de serveurs Web). Étant donné que le serveur qui exécute global.asax peut être différent de celui exécutant la page d'erreur personnalisée, le stockage de l'objet exception dans Application n'est pas fiable.
Je cherche toujours une solution fiable à ce problème dans une configuration de batterie de serveurs Web et/ou une bonne explication de la part de MS indiquant pourquoi vous ne pouvez pas capturer l'exception avec Server.GetLastError sur la page d'erreur personnalisée, comme vous le pouvez. dans global.asax Application_Error.
P.S. Il est dangereux de stocker des données dans la collection d'applications sans d'abord les verrouiller, puis les déverrouiller.
Ceci concerne les 2 sujets ci-dessous, je veux obtenir à la fois GetHtmlErrorMessage et Session on Error.
La session est nulle après ResponseRewrite
Pourquoi HttpContext.Session est-il null lorsque redirectMode = ResponseRewrite
J'ai essayé et voir une solution qui n'a pas besoin de Server.Transfer() or Response.Redirect()
Premièrement: supprimez ResponseRewrite dans web.config
Web.config
<customErrors defaultRedirect="errorHandler.aspx" mode="On" />
Alors Global.asax
void Application_Error(object sender, EventArgs e)
{
if(Context.IsCustomErrorEnabled)
{
Exception ex = Server.GetLastError();
Application["TheException"] = ex; //store the error for later
}
}
Puis 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
}
Pour les références
http://www.developer.com/net/asp/article.php/3299641/ServerTransfer-Vs-ResponseRedirect.htm
Cela a fonctionné pour moi. dans MVC 5
dans ~\Global.asax
void Application_Error(object sender, EventArgs e)
{
FTools.LogException();
Response.Redirect("/Error");
}
dans ~\Controllers
Créer ErrorController.cs
using System.Web.Mvc;
namespace MVC_WebApp.Controllers
{
public class ErrorController : Controller
{
// GET: Error
public ActionResult Index()
{
return View("Error");
}
}
}
dans ~\Models
Créer 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;
}
}
}
dans ~\Views
Créer un dossier Error
et dans ~\Views\Error
Créer 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>
}
}
Si vous entrez cette adresse localhost/Error
Source: Microsoft ASP.Net
Je pense que vous avez deux options ici.
vous pouvez stocker la dernière exception dans la session et la récupérer depuis votre page d'erreur personnalisée; ou vous pouvez simplement rediriger vers votre page d'erreur personnalisée dans l'événement Application_error. Si vous choisissez cette dernière option, vous voulez vous assurer que vous utilisez la méthode Server.Transfer.