Я избегаю подхода ASP.NET по умолчанию для перенаправления на ошибки (как это делают многие люди). Чистый код AJAX и SEO являются одними из причин.
Однако, я использую следующий метод для этого, и кажется, что я могу потерять HttpContext.Current.Items
в передаче?
<httpErrors errorMode="Custom" existingResponse="Replace">
<remove statusCode="401" />
<remove statusCode="403" />
<remove statusCode="404" />
<remove statusCode="500" />
<error statusCode="401" responseMode="ExecuteURL" path="/Account/SignIn" />
<error statusCode="403" responseMode="ExecuteURL" path="/Site/Forbidden" />
<error statusCode="404" responseMode="ExecuteURL" path="/Site/NotFound" />
<error statusCode="500" responseMode="ExecuteURL" path="/Site/Error" />
</httpErrors>
Я предположил, что он просто выполнил a Server.Transfer()
под обложками, которые я понимаю, сохраняет Items
. (См.: Область HttpContext.Current.Items и http://weblog.west-wind.com/posts/2010/Jan/20/HttpContextItems-and-ServerTransferExecute)
Но я также захватываю что-то в Items
перед "ExecuteURL" и извлекаю/выводил его после передачи (или что-то еще), и, похоже, он исчезает. Я наблюдал, как он входит в коллекцию Items
, я вижу, что Count
raise до 5, а затем, когда значение извлекается, в коллекции есть только 2 элемента.
Что происходит?
Если вы хотите больше узнать о том, что я делаю, и рекомендовать альтернативную реализацию, я открыт для нее. Я использую это, чтобы вставить идентификатор ошибки ELMAH в ViewModel таким образом, чтобы он был свободен от условий гонки. (т.е. общий обходной путь для этого, который я заменяю, состоит в том, чтобы просто отображать самую последнюю ошибку.) Здесь мой код:
Global.asax
protected void ErrorLog_Logged(object sender, ErrorLoggedEventArgs args) {
ElmahSupplement.CurrentId = args.Entry.Id;
}
void ErrorLog_Filtering(object sender, ExceptionFilterEventArgs e) {
if (ElmahSupplement.IsNotFound(e.Exception)) {
ElmahSupplement.LogNotFound((e.Context as HttpContext).Request);
e.Dismiss();
}
}
SiteController.cs
public virtual ActionResult Error() {
Response.StatusCode = 500;
return View(MVC.Site.Views.Error, ElmahSupplement.CurrentId);
}
ElmahSupplement.cs
public class ElmahSupplement {
// TODO: This is a rather fragile way to access this info
private static readonly Guid contextId = new Guid("A41A67AA-8966-4205-B6C1-14128A653F21");
public static string CurrentId {
get {
return
// Elmah 1.2 will fail to log when enumerating form values that raise RequestValidationException (angle brackets)
// https://code.google.com/p/elmah/issues/detail?id=217
// So this id could technically be empty here
(HttpContext.Current.Items[contextId] as string);
}
set {
HttpContext.Current.Items[contextId] = value;
}
}
public static void LogNotFound(HttpRequest request) {
var context = RepositoryProxy.Context;
context.NotFoundErrors.Add(new NotFoundError {
RecordedOn = DateTime.UtcNow,
Url = request.Url.ToString(),
ClientAddress = request.UserHostAddress,
Referrer = request.UrlReferrer == null ? "" : request.UrlReferrer.ToString()
});
context.SaveChanges();
}
public static bool IsNotFound(Exception e) {
HttpException he = e as HttpException;
return he != null && he.GetHttpCode() == 404;
}
}