【发布时间】:2010-11-29 15:51:33
【问题描述】:
我有一个 HttpModule,我将几个不同的在线资源拼凑在一起,形成了一个(大部分)既适用于传统 ASP.NET 应用程序,也适用于 ASP.NET MVC 应用程序的东西。其中最大的一部分来自 CodePlex 上的 kigg 项目。我的问题是由于缺少图像而处理 404 错误。在下面的代码中,我必须显式查找通过 HttpContext 的 Request 对象中的 AcceptedTypes 集合请求的图像。如果我不进行此检查,即使缺少图像也会导致重定向到我在 Web.config 部分中定义的 404 页面。
这种方法的问题在于(除了它闻起来的事实之外)这仅适用于图像。我基本上必须对我不希望这种重定向行为发生的每一种可以想象的内容类型执行此操作。
看看下面的代码,有人可以推荐某种重构方式,让它对非页面请求更加宽容吗?我仍然希望它们出现在 IIS 日志中(因此我可能不得不删除 ClearError() 调用),但我认为损坏的图像不会影响用户体验,以至于将它们重定向到错误页面。
代码如下:
/// <summary>
/// Provides a standardized mechanism for handling exceptions within a web application.
/// </summary>
public 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 += this.OnError;
}
#endregion
/// <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 void OnError(object source, EventArgs e)
{
var httpContext = HttpContext.Current;
var imageRequestTypes =
httpContext.Request.AcceptTypes.Where(a => a.StartsWith("image/")).Select(a => a.Count());
if (imageRequestTypes.Count() > 0)
{
httpContext.ClearError();
return;
}
var lastException = HttpContext.Current.Server.GetLastError().GetBaseException();
var httpException = lastException as HttpException;
var statusCode = (int)HttpStatusCode.InternalServerError;
if (httpException != null)
{
statusCode = httpException.GetHttpCode();
if ((statusCode != (int)HttpStatusCode.NotFound) && (statusCode != (int)HttpStatusCode.ServiceUnavailable))
{
// TODO: Log exception from here.
}
}
var redirectUrl = string.Empty;
if (httpContext.IsCustomErrorEnabled)
{
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)
{
httpContext.Server.Transfer(redirectUrl);
}
else
{
var uriBuilder = new UriBuilder(
httpContext.Request.Url.Scheme,
httpContext.Request.Url.Host,
httpContext.Request.Url.Port,
httpContext.Request.ApplicationPath);
uriBuilder.Path += redirectUrl;
string path = httpContext.Server.UrlDecode(uriBuilder.Uri.PathAndQuery);
HttpContext.Current.RewritePath(path, false);
IHttpHandler httpHandler = new MvcHttpHandler();
httpHandler.ProcessRequest(HttpContext.Current);
}
}
}
}
任何反馈都将不胜感激。我目前正在使用的应用程序是一个 ASP.NET MVC 应用程序,但就像我提到的那样,它是为使用 MVC 处理程序而编写的,但仅当 CurrentHandler 属于该类型时。
编辑:我忘了提到在这种情况下的“hack”将是 OnError() 中的以下几行:
var imageRequestTypes =
httpContext.Request.AcceptTypes.Where(a => a.StartsWith("image/")).Select(a => a.Count());
if (imageRequestTypes.Count() > 0)
{
httpContext.ClearError();
return;
}
【问题讨论】:
-
您是否考虑过使用现有的错误日志库之一,而不是构建自己的错误日志记录模块,例如 ELMAH (code.google.com/p/elmah) 或 ASP.NET 健康监控 (msdn.microsoft.com/en-us/library/ms998306.aspx) ? ELMAH 具有丰富的错误过滤 API,如果需要,您可以在 Web.config 中以声明方式或通过代码指定。
-
Scott,我确实考虑过并且过去使用过 ELMAH。这更像是一次编码练习。
标签: asp.net asp.net-mvc error-handling http-status-code-404 httpmodule