Search code examples
c#asp.net-mvcmodel-view-controllerglobal-asaxasp.net-mvc-5.2

Server.GetLastError() returns null when Internal Server Error (500) occurs


I am making a module that logs the errors to a .log file and save it to the database. I am only triggering the logging under this following instances:

  1. Ajax errors. More specifically, error 500 status code that has occurred on the controller.
  2. When the user tries to go to a non-existent page within the web application

The Problem:

My 2nd goal works very well but I am having trouble with my 1st goal. The Server.GetLastError() returns null when an Internal Server error has occurred. In addition to this, it doesn't redirect the custom pages, it redirects on the _ViewStart.cshtml instead.

I have tried the solutions from this post but none seems to work. It still returns null and not the exception message. This only happens on Internal Server error (500) I think. Below is my code, the web config, and a test endpoint to simulate an error.

Global.asax

void Application_Error(object sender, EventArgs e)
{
    try
    {
        // Code that runs when an unhandled error occurs
        HttpException lastErrorWrapper = Server.GetLastError() as HttpException;

        Exception lastError = lastErrorWrapper;
        if (lastErrorWrapper.InnerException != null)
            lastError = lastErrorWrapper.InnerException;

        string lastErrorTypeName = lastError.GetType().ToString();
        string lastErrorMessage = lastError.Message;
        string lastErrorStackTrace = lastError.StackTrace;
        
        // Creation of the log and the log file containing the error
        LogFileModel logFile = helpers.CreateLogFile(lastErrorTypeName, lastErrorMessage, lastErrorStackTrace);
        helpers.InsertActivityLog_Error(2, "", "Web portal error.", logFile.file, logFile.fileSize, logFile.fileName);
    }
    catch (Exception) { }
}

Web.config

<system.web>
    <customErrors defaultRedirect="~/Error/ErrorHasOccured" mode="RemoteOnly" redirectMode="ResponseRewrite">
        <error statusCode="404" redirect="~/Error/PageNotFound"/>
        <error statusCode="500" redirect="~/Error/ErrorHasOccured"/>
    </customErrors>
</system.web>

Test end-point on one of my Controllers

public ActionResult test() {
    throw new Exception("This is a test error!");
    return new HttpStatusCodeResult(System.Net.HttpStatusCode.OK);
}

If I missed something on the post I linked above, please let me know. Any help would be appreciated. Thanks!


Solution

  • It seems like ASP.Net does not allow error 500 on Server.GetLastError() for some reason. If somebody knows why this is the case or if I am wrong, feel free to comment here so everybody will know.

    MS Docs doesn't clearly explain to me why this is the case so I made a workaround instead. I used the object sender parameter which holds the information I needed. I fetched the error message and the stack trace from there and passed it to my function that creates the log file to the database.

    void Application_Error(object sender, EventArgs e)
    {
        var senderValue = (HttpApplication)sender;
    
        string lastErrorTypeName = string.Empty;
        string lastErrorMessage = string.Empty;
        string lastErrorStackTrace = string.Empty;
    
        try
        {
            HttpException lastErrorWrapper = Server.GetLastError() as HttpException;
    
            Exception lastError = lastErrorWrapper;
            if (lastErrorWrapper.InnerException != null)
                lastError = lastErrorWrapper.InnerException;
    
            lastErrorTypeName = lastError.GetType().ToString();
            lastErrorMessage = lastError.Message;
            lastErrorStackTrace = lastError.StackTrace;
        }
        catch (Exception) 
        {
            lastErrorTypeName = "InternalError";
            lastErrorMessage = senderValue.Context.Error.Message;
            lastErrorStackTrace = senderValue.Context.Error.StackTrace;
        }
    
        // Create log file and store to database
        try
        {
            LogFileModel logFile = helpers.CreateLogFile(lastErrorTypeName, lastErrorMessage, lastErrorStackTrace);
            helpers.InsertActivityLog_Error(2, "", "Web portal error.", logFile.file, logFile.fileSize, logFile.fileName);
        }
        catch (Exception) { }
    }
    

    I know this is not as robust as using the Server.GetLastError(). If you find a better solution, please feel free to answer.

    Thanks!