Tôi có một HttpModule mà tôi đã đặt cùng nhau từ cobbling một vài nguồn khác nhau trực tuyến với nhau thành một cái gì đó (chủ yếu) làm việc với cả hai ứng dụng ASP.NET truyền thống, cũng như ASP.NET MVC các ứng dụng. Phần lớn nhất của điều này xuất phát từ dự án kigg trên CodePlex. Vấn đề của tôi là đối phó với lỗi 404 do một hình ảnh bị thiếu. Trong đoạn mã sau, tôi đã phải tìm kiếm một cách rõ ràng một hình ảnh đang được yêu cầu thông qua bộ sưu tập AcceptedTypes trong đối tượng Request của HttpContext. Nếu tôi không đặt trong kiểm tra này, ngay cả một hình ảnh bị mất đang gây ra một chuyển hướng đến trang 404 được định nghĩa trong phần của tôi trong Web.config.HttpModule để xử lý lỗi và thiếu hình ảnh
Vấn đề với cách tiếp cận này là (ngoài thực tế nó có mùi) là đây chỉ là cho hình ảnh. Tôi về cơ bản sẽ phải làm điều này với mọi loại nội dung đơn lẻ có thể tưởng tượng được rằng tôi không muốn hành vi chuyển hướng này xảy ra.
Nhìn vào mã bên dưới, ai đó có thể đề xuất một số loại tái cấu trúc có thể cho phép nó khoan dung hơn với các yêu cầu không phải trang? Tôi vẫn muốn chúng trong các bản ghi IIS (vì vậy tôi có lẽ sẽ phải loại bỏ cuộc gọi ClearError()), nhưng tôi không nghĩ rằng một hình ảnh bị hỏng sẽ ảnh hưởng đến trải nghiệm người dùng đến điểm chuyển hướng chúng đến trang lỗi.
mã sau:
/// <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);
}
}
}
}
Bất kỳ thông tin phản hồi sẽ được đánh giá. Các ứng dụng mà tôi hiện đang làm điều này với là một ứng dụng ASP.NET MVC, nhưng như tôi đã đề cập nó được viết để làm việc với một trình xử lý MVC, nhưng chỉ khi CurrentHandler là loại đó.
Edit: tôi quên đề cập đến "hack" trong trường hợp này sẽ là những dòng sau trong onerror():
var imageRequestTypes =
httpContext.Request.AcceptTypes.Where(a => a.StartsWith("image/")).Select(a => a.Count());
if (imageRequestTypes.Count() > 0)
{
httpContext.ClearError();
return;
}
Thay vì xây dựng mô-đun lỗi đăng nhập của riêng bạn, bạn đã xem xét việc sử dụng một trong các thư viện ghi lỗi hiện có không, chẳng hạn như ELMAH (http://code.google.com/p/elmah/) hoặc ASP.NET Health Monitoring (http://msdn.microsoft.com/ en-us/library/ms998306.aspx)? ELMAH có API lọc lỗi phong phú, bạn có thể chỉ định khai báo trong Web.config hoặc thông qua mã, nếu cần. –
Scott, tôi chắc chắn đã xem xét nó và đã sử dụng ELMAH trong quá khứ. Đây là một bài tập viết mã hơn bất cứ thứ gì khác. –