最终,问题是由于没有区分传统ASP.NET应用程序和ASP.NET MVC应用程序提供的不同类型的上下文。通过提供一个检查来确定我正在处理的上下文类型,我能够做出相应的响应。
我为httptransfer和mvctransfer添加了单独的方法,允许我重定向到错误页面,特别是在需要时。我还改变了周围的逻辑,这样我就可以很容易地在本地和开发机器上获得我的ysod,而不需要处理程序接受异常。
除了用于将异常记录到数据库的代码(由todo注释表示)之外,我们使用的最终代码是:
using System;
using System.Net;
using System.Security.Principal;
using System.Web;
using System.Web.Configuration;
using System.Web.Mvc;
using Diagnostics;
/// <summary>
/// Provides a standardized mechanism for handling exceptions within a web application.
/// </summary>
public sealed class ErrorHandlerModule : IHttpModule
{
#region Public Methods
/// <summary>
/// Disposes of the resources (other than memory) used by the module that implements
/// <see cref="T:System.Web.IHttpModule"/>.
/// </summary>
public void Dispose()
{
}
/// <summary>
/// Initializes a module and prepares it to handle requests.
/// </summary>
/// <param name="context">
/// An <see cref="T:System.Web.HttpApplication"/> that provides access to the methods, properties, and events
/// common to all application objects within an ASP.NET application.</param>
public void Init(HttpApplication context)
{
context.Error += OnError;
}
#endregion
#region Private Static Methods
/// <summary>
/// Performs a Transfer for an MVC request.
/// </summary>
/// <param name="url">The URL to transfer to.</param>
/// <param name="currentContext">The current context.</param>
private static void HttpTransfer(string url, HttpContext currentContext)
{
currentContext.Server.TransferRequest(url);
}
/// <summary>
/// Performs a Transfer for an MVC request.
/// </summary>
/// <param name="url">The URL to transfer to.</param>
/// <param name="currentContext">The current context.</param>
private static void MvcTransfer(string url, HttpContext currentContext)
{
var uriBuilder = new UriBuilder(
currentContext.Request.Url.Scheme,
currentContext.Request.Url.Host,
currentContext.Request.Url.Port,
currentContext.Request.ApplicationPath);
uriBuilder.Path += url;
string path = currentContext.Server.UrlDecode(uriBuilder.Uri.PathAndQuery);
HttpContext.Current.RewritePath(path, false);
IHttpHandler httpHandler = new MvcHttpHandler();
httpHandler.ProcessRequest(HttpContext.Current);
}
#endregion
#region Private Methods
/// <summary>
/// Called when an error occurs within the application.
/// </summary>
/// <param name="source">The source.</param>
/// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
private static void OnError(object source, EventArgs e)
{
var httpContext = HttpContext.Current;
var lastException = HttpContext.Current.Server.GetLastError().GetBaseException();
var httpException = lastException as HttpException;
var statusCode = (int)HttpStatusCode.InternalServerError;
if (httpException != null)
{
if (httpException.Message == "File does not exist.")
{
httpContext.Response.StatusCode = (int)HttpStatusCode.NotFound;
httpContext.ClearError();
return;
}
statusCode = httpException.GetHttpCode();
}
if ((statusCode != (int)HttpStatusCode.NotFound) && (statusCode != (int)HttpStatusCode.ServiceUnavailable))
{
// TODO : Your error logging code here.
}
var redirectUrl = string.Empty;
if (!httpContext.IsCustomErrorEnabled)
{
return;
}
var errorsSection = WebConfigurationManager.GetSection("system.web/customErrors") as CustomErrorsSection;
if (errorsSection != null)
{
redirectUrl = errorsSection.DefaultRedirect;
if (httpException != null && errorsSection.Errors.Count > 0)
{
var item = errorsSection.Errors[statusCode.ToString()];
if (item != null)
{
redirectUrl = item.Redirect;
}
}
}
httpContext.Response.Clear();
httpContext.Response.StatusCode = statusCode;
httpContext.Response.TrySkipIisCustomErrors = true;
httpContext.ClearError();
if (!string.IsNullOrEmpty(redirectUrl))
{
var mvcHandler = httpContext.CurrentHandler as MvcHandler;
if (mvcHandler == null)
{
try
{
HttpTransfer(redirectUrl, httpContext);
}
catch (InvalidOperationException)
{
MvcTransfer(redirectUrl, httpContext);
}
}
else
{
MvcTransfer(redirectUrl, httpContext);
}
}
}
#endregion
}