Ответ 1
Все необработанные исключения, наконец, прошли через Application_Error в global.asax. Таким образом, чтобы дать общее сообщение об исключении или выполнить операции регистрации, см. Application_Error.
У меня есть сайт, построенный на С#.NET, который имеет тенденцию создавать довольно устойчивый поток тайм-аутов SQL из различных пользовательских элементов управления, и я хочу легко поместить какой-то код, чтобы поймать все необработанные исключения и отправить их тому, что может их зарегистрировать и отобразить дружественное сообщение пользователю.
Как я, с минимальными усилиями, поймаю все необработанные исключения?
этот вопрос кажется невозможным, но для меня это не имеет смысла (и об .NET 1.1 в приложениях Windows):
Все необработанные исключения, наконец, прошли через Application_Error в global.asax. Таким образом, чтобы дать общее сообщение об исключении или выполнить операции регистрации, см. Application_Error.
Если вам нужно поймать исключения во всех потоках, лучшим aproach является реализация UnhandledExceptionModule и добавление его в ваше приложение, посмотрите здесь для примера
Используйте метод Application_Error в файле Global.asax. Внутри реализации метода Application_Error вызовите Server.GetLastError(), запишите сведения об исключении, возвращенном Server.GetLastError(), но вы хотите.
например.
void Application_Error(object sender, EventArgs e)
{
// Code that runs when an unhandled error occurs
log4net.ILog log = log4net.LogManager.GetLogger(typeof(object));
using (log4net.NDC.Push(this.User.Identity.Name))
{
log.Fatal("Unhandled Exception", Server.GetLastError());
}
}
Не уделяйте слишком много внимания материалам log4net, Server.GetLastError() является самым полезным битом, записывайте данные, но вы предпочитаете.
Проект проекта ELMAH стоит попробовать, его список функций включает в себя:
ELMAH (модули регистрации ошибок и Handlers) является общесистемной ошибкой объект регистрации, который полностью подключаемый. Он может быть динамически добавлен к запущенному веб-приложению ASP.NET, или даже всех веб-приложений ASP.NET на машине, без каких-либо повторная компиляция или повторное развертывание.
- Регистрация почти всех необработанных исключений.
- Веб-страница для удаленного просмотра всего журнала перекодированных исключений.
- Веб-страница для удаленного просмотра полной информации о любом зарегистрированном исключение.
- Во многих случаях вы можете просмотреть оригинальный желтый экран смерти, который ASP.NET, сгенерированный для заданного исключение, даже в режиме customErrors выключен.
- Уведомление по электронной почте о каждой ошибке в момент ее возникновения.
- RSS-канал последних 15 ошибок из журнала.
- Ряд реализаций хранилища для журнала
Подробнее об использовании ELMAH из dotnetslackers
Вы можете подписаться на событие AppDomain.CurrentDomain.UnhandledException
.
Вероятно, важно отметить, что вы не предполагаются, чтобы поймать необработанные исключения. Если у вас возникли проблемы с таймаутом SQL, вы должны их специально поймать.
Вы имеете в виду обращение с ним во всех потоках, в том числе и с помощью стороннего кода? Внутри "известных" потоков просто ловите Exception
в верхней части стека.
Я бы рекомендовал посмотреть log4net и посмотреть, подходит ли это для части ведения журнала вопроса.
При использовании .net 2.0 framework я использую встроенные службы мониторинга работоспособности. Здесь есть хорошая статья, описывающая этот метод: http://aspnet.4guysfromrolla.com/articles/031407-1.aspx
Если вы застряли с фреймворком 1.0, я бы использовал ELMAH: http://msdn.microsoft.com/en-us/library/aa479332.aspx
надеюсь, что это поможет
Есть две части для обработки и идентификации этой проблемы.
Определение
Это то, что вы делаете, когда исключение, наконец, поймано, а не обязательно там, где оно выбрано. Таким образом, исключение на этом этапе должно иметь достаточную контекстную информацию для вас, чтобы определить, что проблема была
Работа
Для обработки вы можете a) добавить HttpModeule. Видеть http://www.eggheadcafe.com/articles/20060305.asp Я бы предложил этот подход только в том случае, если нет абсолютно никакого контекста informaatn, и может быть выпущено IIS/aspnet, Короче говоря, для катастрофических ситуаций
b) Создайте абстрактный класс, называемый AbstractBasePage, который происходит из класса Page и имеет все ваши классы codebehind, полученные из AbstractBasePage
The AbstractBasePage может реализовать этот делегат Page.Error, чтобы все исключения, которые просачивались через n-ярусную архитектуру, могли быть пойманы здесь (и, возможно, зарегистрированы)
Я бы предложил эту причину для тех исключений, о которых вы говорите (SQlException), достаточно информации контекста, чтобы определить, что это таймаут и принять возможные меры. Это действие может включать перенаправление пользователя на страницу пользовательских ошибок с соответствующим сообщением для каждого отдельного исключения (Sql, webservice, тайм-ауты асинхронного вызова и т.д.).
Спасибо RVZ
Ошибки таймаута обычно возникают, если вы не принудительно закрываете свои sqlconnections.
поэтому, если у вас есть
try {
conn.Open();
cmd.ExecuteReader();
conn.Close();
} catch (SqlException ex) {
//do whatever
}
Если что-то пойдет не так с этим ExecuteReader, ваше соединение не будет закрыто. Всегда добавляйте блок finally.
try {
conn.Open();
cmd.ExecuteReader();
conn.Close();
} catch (SqlException ex) {
//do whatever
} finally {
if(conn.State != ConnectionState.Closed)
conn.Close();
}
Один короткий ответ - использовать (анонимные) методы делегата с общим кодом обработки при вызове делегата.
Справочная информация. Если вы нацелились на слабые места или имеете код обработки ошибок шаблона, вам необходимо универсально применить к определенному классу проблем, и вы не хотите писать тот же файл try..catch для каждого местоположения вызова, (например, обновление определенного элемента управления на каждой странице и т.д.).
Тематическое исследование: точка боли - это веб-формы и сохранение данных в базе данных. У нас есть элемент управления, который отображает сохраненный статус для пользователя, и мы хотели иметь общий код обработки ошибок, а также общий дисплей без копирования-повторного использования на каждой странице. Кроме того, каждая страница делала это самостоятельно, поэтому единственной действительно общей частью кода была обработка и отображение ошибок.
Теперь, прежде чем захлопнуться, это не замена уровня доступа к данным и кода доступа к данным. Все, что все еще предполагалось, существует, хорошее разделение n-уровня и т.д. Этот код является UI-слоем, который позволяет нам писать чистый код пользовательского интерфейса, а не повторяться. Мы очень верим в исключения, но не исключаем, что некоторые исключения не требуют, чтобы пользователь получал общую страницу ошибок и терял работу. Там будут тайм-ауты sql, серверы идут вниз, взаимоблокировки и т.д.
Решение. То, как мы это делали, состояло в том, чтобы передать анонимный делегат методу в пользовательском элементе управления и по сути добавить блок try с помощью анонимных делегатов.
// normal form code.
private void Save()
{
// you can do stuff before and after. normal scoping rules apply
saveControl.InvokeSave(
delegate
{
// everywhere the save control is used, this code is different
// but the class of errors and the stage we are catching them at
// is the same
DataContext.SomeStoredProcedure();
DataContext.SomeOtherStoredProcedure();
DataContext.SubmitChanges();
});
}
Сам метод SaveControl имеет такой метод, как:
public delegate void SaveControlDelegate();
public void InvokeSave(SaveControlDelegate saveControlDelegate)
{
// I've changed the code from our code.
// You'll have to make up your own logic.
// this just gives an idea of common handling.
retryButton.Visible = false;
try
{
saveControlDelegate.Invoke();
}
catch (SqlTimeoutException ex)
{
// perform other logic here.
statusLabel.Text = "The server took too long to respond.";
retryButton.Visible = true;
LogSqlTimeoutOnSave(ex);
}
// catch other exceptions as necessary. i.e.
// detect deadlocks
catch (Exception ex)
{
statusLabel.Text = "An unknown Error occurred";
LogGenericExceptionOnSave(ex);
}
SetSavedStatus();
}
Это старый вопрос, но лучший метод (для меня) здесь не указан. Итак, вот мы:
ExceptionFilterAttribute - это приятное и легкое решение для меня. Источник: http://weblogs.asp.net/fredriknormen/asp-net-web-api-exception-handling.
public class ExceptionHandlingAttribute : ExceptionFilterAttribute
{
public override void OnException(HttpActionExecutedContext context)
{
var exception = context.Exception;
if(exception is SqlTimeoutException)
{
//do some handling for this type of exception
}
}
}
И прикрепите его к f.e. HomeController:
[ExceptionHandling]
public class HomeController: Controller
{
}