У меня есть HttpModule, который я собрал вместе из нескольких различных источников в Интернете в нечто, что (в основном) работает как с традиционными приложениями ASP.NET, так и с ASP.NET MVC Приложения. Большая часть этого происходит от проекта kigg на CodePlex. Моя проблема связана с 404 ошибками из-за недостающего изображения. В следующем коде мне пришлось явно искать изображение, запрашиваемое через коллекцию AcceptedTypes в объекте Request HttpContext. Если я не поставил эту проверку, даже отсутствующее изображение вызывает перенаправление на страницу 404, определенную в моем разделе в Web.config.HttpModule для обработки ошибок и отсутствующих изображений
Проблема с этим подходом заключается в том, что (помимо того, что он пахнет) заключается в том, что это только для изображений. В основном я должен был бы сделать это с каждым единственным типом контента, который можно представить, что я не хочу, чтобы это поведение перенаправления происходило.
Глядя на код ниже, может кто-то порекомендовать какой-то рефакторинг, который может позволить ему быть более снисходительным к нестраничным запросам? Я бы все еще хотел, чтобы они были в журналах 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 имеет этот тип.
Edit: Я забыл упомянуть о «взломать» в данном случае было бы следующие строки в OnError():
var imageRequestTypes =
httpContext.Request.AcceptTypes.Where(a => a.StartsWith("image/")).Select(a => a.Count());
if (imageRequestTypes.Count() > 0)
{
httpContext.ClearError();
return;
}
Вместо того, чтобы создать свой собственный модуль протоколирования ошибок, рассмотрели ли вы использование одной из существующих библиотек регистрации ошибок, таких как ELMAH (http://code.google.com/p/elmah/) или мониторинг работоспособности ASP.NET (http://msdn.microsoft.com/) ан-нас/библиотека/ms998306.aspx)? ELMAH имеет богатый API фильтрации ошибок, который можно указать декларативно в Web.config или через код, если это необходимо. –
Скотт, я определенно подумал об этом и использовал ELMAH в прошлом. Это было скорее упражнением по кодированию, чем чем-либо еще. –