Я все еще немного запутался во всех различных решениях и в том, как атрибуты могут мешать друг другу, но я выбрал это решение:
public class LogErrorsAttribute: FilterAttribute, IExceptionFilter
{
#region IExceptionFilter Members
void IExceptionFilter.OnException(ExceptionContext filterContext)
{
if (filterContext != null && filterContext.Exception != null)
{
string controller = filterContext.RouteData.Values["controller"].ToString();
string action = filterContext.RouteData.Values["action"].ToString();
string loggerName = string.Format("{0}Controller.{1}", controller, action);
log4net.LogManager.GetLogger(loggerName).Error(string.Empty, filterContext.Exception);
}
}
#endregion
}
Я все еще использую атрибут [HandleError], как описано в исходном вопросе, и я просто украшаю каждый контроллер атрибутом [LogErrors].
Это работает для меня, так как ведет журнал ошибок в одном месте и не приводит к многократной регистрации повторяющихся исключений (что произойдет, если я расширю [HandleError] и использую атрибут в нескольких местах).
Я не думаю, что будет возможно объединить регистрацию исключений и обработку ошибок в одном атрибуте или классе, без того, чтобы он стал очень утомительным и сложным, или не влиял на использование [HandleError]
Но это работает для меня, так как я украшаю каждый контроллер только один раз, с атрибутом [LogErrors], и украшаю Контроллеры и Действия с помощью [HandleError] именно так, как я хочу, без того, чтобы они мешали друг другу.
Обновление:
Вот пример того, как я его использую:
[LogErrors(Order = 0)]
[HandleError(Order = 99)]
public class ContactController : Controller
{
public ActionResult Index()
{
return View(Views.Index);
}
public ActionResult Directions()
{
return View(Views.Directions);
}
public ActionResult ContactForm()
{
FormContactMessage formContactMessage = new FormContactMessage();
return View(Views.ContactForm,formContactMessage);
}
[HandleError(ExceptionType = typeof(SmtpException), View = "MessageFailed", Order = 1)]
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult ContactForm(FormContactMessage formContactMessage)
{
if (ModelState.IsValid)
{
if (formContactMessage.IsValid)
{
SmtpClient client = new SmtpClient();
MailAddress recipientAddress = new MailAddress(Properties.Settings.Default.ContactFormRecipientEmailAddress);
MailAddress senderAddress = new MailAddress(Properties.Settings.Default.ContactFormSenderEmailAddress);
MailMessage mailMessage = formContactMessage.ToMailMessage(recipientAddress, senderAddress);
client.Send(mailMessage);
return View("MessageSent");
}
else
{
ModelState.AddRuleViolations(formContactMessage.GetRuleViolations());
}
}
return View(Views.ContactForm, formContactMessage);
}
private static class Views
{
public static string Index { get { return "Index"; } }
public static string Directions { get { return "Directions"; } }
public static string ContactForm { get { return "ContactForm"; } }
}
}
В приведенном выше коде SmtpExceptions в перегрузке действия ContactForm
обрабатываются очень специфическим способом - пользователю предоставляется ViewPage, специфичный для отправленных сообщений с ошибками, в данном случае он называется «MessageFailed». Все остальные исключения обрабатываются поведением по умолчанию [HandleError]. Также обратите внимание, что сначала происходит регистрация ошибок, а затем обработка ошибок. На это указывает следующее:
[LogErrors(Order = 0)]
[HandleError(Order = 99)]
Обновление:
Существует альтернативное решение с очень хорошим объяснением. Я рекомендую прочитать его, чтобы лучше понять связанные с этим вопросы.
Атрибут HandleError ASP.NET MVC, пользовательские страницы ошибок и исключения журналирования
(Спасибо Скотту Шепарду ниже, который предоставил ссылку в ответе ниже).