customErrors vs Custom modules
Asked Answered
D

3

8

I've currently got httpErrors setup to deal with 500's here:-

<httpErrors errorMode="Custom" existingResponse="Replace">
        ......
        <remove statusCode="500"/>
        <error statusCode="500" path="/server-error" responseMode="ExecuteURL"/>
</httpErrors>

This works fine, but in the case where iis receives the error I still get the yellow screen of death. An example is when entity framework can not connect to the database and I receive:-

Cannot open database "Test-DB" requested by the login.
The login failed.
Login failed for user 'sa'.

I've setup customErrors to deal with this:-

<customErrors mode="On" defaultRedirect="error.html" redirectMode="ResponseRedirect">
        <error statusCode="500" redirect="error.html" />
</customErrors>

which works as expected as long as there is no modules without preCondition="managedHandler".

I have a few modules which deal with images and css files and are in the same project.

<modules runAllManagedModulesForAllRequests="false">
        <add name="ErrorLog" type="Elmah.ErrorLogModule, Elmah" preCondition="managedHandler" />
        <add name="ErrorFilter" type="Elmah.ErrorFilterModule, Elmah" preCondition="managedHandler" />
        <add name="ImageHandler" type="foo.bar.ProductImageHandlerHttpModule" />
        <add name="CustomCssHandler" type="foo.bar.CustomCssHttpModule" />
        <add name="Glimpse" type="Glimpse.AspNet.HttpModule, Glimpse.AspNet" preCondition="integratedMode" />
</modules>

Comment these out and I get the error.html, keep them in and I get

Runtime Error
Description: An exception occurred while processing your request. Additionally, another exception occurred while executing the custom error page for the first exception. The request has been terminated.

showing that a module from the project is also erroring when trying to show the error.html.

Does anyone know a fix/workaround?

Disoperation answered 20/10, 2016 at 10:13 Comment(2)
Hi @BenG,I tried to reproduce the issue. I think problem is with preCondition="managedHandler" even though documentation for msdn.microsoft.com/en-us/library/ms690693(v=vs.90).aspx says it should not run modules which has preCondition="managedHandler" for non managed such html it still does. I am just trying to find out why IIS still runs Modules for html file which has precondition.Winshell
@MurtazaTahirAli The modules with the pre-condition dont run for me. its the other foo.bar. custom ones which throw the next error.Disoperation
M
1

Its a tough situation - your error comes from HttpModule, which is run for every single request - including request to error.html page. One way is to route static files (such as error.html) just via your server - and ignore them on .NET level; this may not be always possible (sometimes handling static files on .NET level is handy). The only other way I can think off is hook in global.asax to error event and handle it yourself (which will ignore the customErrors)

Something like:

public class Global : System.Web.HttpApplication
{
    protected void Application_Error(object sender, EventArgs e)
    {
        // is there an error ?
        var error = Server.GetLastError();
        if (error != null)
        {
            // mark the error as - "i'll handle it myself"
            Server.ClearError();
            // load error.html manually & dump it to response
            var content = File.ReadAllText(Server.MapPath("~/error.html"));
            Context.Response.Write(content);
            // set correct error code
            Context.Response.StatusCode = 500;
        }
    }
}

Note: this can be ironed out, but you see the general principle ...

Massenet answered 24/10, 2016 at 7:53 Comment(1)
This didn't fix the issue 100%, as the response is unavailable if you get an error on site startup, but Application_Error seems the most consistent answer and this was first I will award the bounty to you. Thank you.Disoperation
O
0

As @Ondrej said, another error occurred when handling the custom error page comes from unhandled exception on HttpModule, thus it is necessary to either skip or bypassing customErrors section on web.config file.

This code also includes how to skip custom errors generated from IIS, besides generating custom HTML error page:

protected void Application_Error(Object sender, EventArgs e)
{
    // Get last error occurred
    var exception = Server.GetLastError();

    // catch unhandled exceptions
    if (exception is HttpUnhandledException)
    {
        // handle the error by ASP .NET itself
        Server.ClearError();
        
        // write status code handling
        HttpContext.Current.Response.WriteFile(Server.MapPath("~/error.html"));
        HttpContext.Current.Response.StatusCode = 500;
        HttpContext.Current.Response.StatusDescription = "Internal Server Error";

        // set ASP .NET handlers instead of using IIS handlers
        HttpContext.Current.Response.TrySkipIisCustomErrors = true;
    }
}

Additionally, to get rid of YSOD pages generated by IIS you may set existingResponse attribute to pass error handling into ASP .NET Application_Error method as this:

<system.webServer>
    <httpErrors errorMode="Custom" existingResponse="PassThrough">
    <remove statusCode="500" />
    <error statusCode="500" responseMode="File" path="/error.html" />
    </httpErrors>
</system.webServer>

The reason behind those settings based from Kanwaljeet Singla's explanation (source here):

existingResponse

Value of this section level property tells custom error module what to do when response text is not blank. If a module call IHttpResponse::SetStatus to set an error code and also sets up response text, existingResponse property tells if custom error module should replace current response text with its own error text or should it let the current response text pass through. Asp.Net and WCF are example of modules which sets error response text. This property can be set to following three values.

  • Replace – This value make custom error module to always replace the error information with text generated by custom error module. If existingResponse is set to “Replace”, errors/exceptions generated by Asp.Net/WCF are replaced by IIS7 errors.

  • PassThrough – If existingResponse is seen as “PassThrough”, custom error module will always pass through responses from modules. This setting will make custom error module return blank response if modules don’t set any text.

  • Auto – This is the default value and tells custom error module to do the right thing. Actual error text seen by clients will be affected depending on value of fTrySkipCustomErrors returned in IHttpResponse::GetStatus call. When TrySkipCustomErrors is set to true, custom error module will let the response pass through but if it is set to false, custom errors module replaces text with its own text. Asp.Net/WCF call IHttpResponse::SetStatus with TrySkipCustomErrors true so that IIS doesn’t override their errors with its own. When effective errorMode is “Detailed” and response is non-empty, this value of existingResponse will act as “PassThrough” regardless of value of TrySkipCustomErrors.

Hopefully this may figure out the essential things when setting custom error page for unhandled exception responses.

MSDN References:

https://msdn.microsoft.com/en-us/library/ms690576(v=vs.90).aspx

https://msdn.microsoft.com/en-us/library/system.web.httpresponse.tryskipiiscustomerrors(v=vs.110).aspx

SO References:

IIS7 Overrides customErrors when setting Response.StatusCode?

How to send status code "500" for generic error page in IIS?

Getting IIS7 'one liner' error when using custom error settings in web.config

Overissue answered 25/10, 2016 at 2:21 Comment(2)
Just tried this, unfortunately I get the error Response is not available in this context. at Response.WriteFile(Server.MapPath("~/error.html"));Disoperation
I realized that Response property on Application_Error method comes from HttpApplication class instead of HttpContext.Current.Response, the current context may necessary to activate Response.WriteFile.Overissue
W
0

It seems if your iis is set with Integrated Mode then Modules will still be run for static files. If you set it to Classic mode it will ignore the managed modules for static files.

Please refer this thread for more infomration see the answer of João Angelo Requests for static files are hitting the managed code in ASP.NET MVC3

The fix is either you changed your handler to not throw exception or you change iis to classic mode so if any handler or other part throws exception and iis redirects to error.html then none of manage module should hit.

Winshell answered 31/10, 2016 at 6:17 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.