Exception Handling Application Block Exception Handler running in ASP.NET cannot call Response.End()

自古美人都是妖i 提交于 2019-12-05 13:52:28

Have a look at ELMAH.
There are lots of articles and how-to's on ELMAH, just google or bing for it :-)

Advantages
+ It logs almost everything
+ Email notification
+ Remote viewing of errors

I would suggest to use that and redirect to a default error page, as Ariel mentioned.

Have a look at this Microsoft explanation. It says it applies to ASP.Net 1.1, but I think it still applies in 2.0. Basically you should call the HttpContext.Current.ApplicationInstance.CompleteRequest method instead.

Also, I'm not sure why you can't catch the ThreadAbortException - why can't you do something like

try {
    // code
} catch (ThreadAbortException)
{
    //do nothing
}

My approach to handling ASP.net exceptions was always to catch it, log it and then redirect to a generic error page with some standard error message (the end user won't care about exceptions or stack traces). You already logged the exception in your policy before your handler so maybe all you have to do is a response redirect to an error page and move the BuildErrorPage logic there. You can pass the handlingInstanceId in the querystring.

Try using Application_Error in the Global.asax to capture any unhandle exceptions thrown by any page in your application.

This may help: http://msdn.microsoft.com/en-us/library/cyayh29d.aspx

Specifically "Your clean-up code must be in the catch clause or the finally clause, because a ThreadAbortException is rethrown by the system at the end of the finally clause, or at the end of the catch clause if there is no finally clause.

You can prevent the system from rethrowing the exception by calling the Thread..::.ResetAbort method. However, you should do this only if your own code caused the ThreadAbortException. "

Note that Response.End and Response.Redirect may throw a ThreadAbortException under certain conditions.

After a lot of testing, I have found only two approaches that work without error.

Solution 1

No change to the current architecture at all. The global exception handler already works as desired. If an explicit catch block is needed in code for any reason (e.g. to render validation errors on an input form), then I will tell developers to call Response.End explicitly, e.g.

try {
    // ...
} catch(Exception ex) {
    if(ExceptionPolicy.HandleException(ex, "Top Level")) {
        throw;
    }
    Response.End();
}

Solution 2

Give up trying to overwrite the current response stream and do a genuine redirect to an error page. This works fine with all six test harness methods. The next problem was finding a way of doing this that required the minimum possible changes to the consuming project and abstracted away all the dirty details.

Step 1 - Add a placeholder ErrorPage.ashx file to the project which contains only a reference to a standard web page handler class and no code-behind.

<%@ WebHandler Class="WebApplicationErrorPage" %>

Step 2 - Redirect to this page in the PageExceptionHandler class, using a session key to pass all required data.

public Exception HandleException(Exception ex, Guid handlingInstanceID) {

    HttpResponse response = HttpContext.Current.Response;
    HttpSessionState session = HttpContext.Current.Session;

    session["ErrorPageText"] = BuildErrorPage(ex, handlingInstanceID);
    response.Redirect(errorPageUrl, false);

    return ex;
}

Step 3 - Make the WebApplicationErrorPage class a really dumb HTTP handler that just writes to the response stream.

public class WebApplicationErrorPage : IHttpHandler, IReadOnlySessionState {

    public bool IsReusable {
        get {
            return true;
        }
    }

    public void ProcessRequest(HttpContext context) {

        response.Clear();
        response.ContentEncoding = Encoding.UTF8;
        response.ContentType = "text/html";
        response.Write((string) context.Session["ErrorPageText"]);
        response.Flush();
    }
}

Conclusion

I think I'll stick with solution 1 because it doesn't involve chopping and changing the existing architecture (implementing solution 2 for real will be a lot more complex than the code snippets above suggest). I'll file away solution 2 for possible use elsewhere.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!