Получение идентификатора ошибки в Elmah после вызова .Raise () - PullRequest
8 голосов
/ 26 октября 2011

Я работаю над приложением MVC3 и использую Elmah для ведения журнала ошибок.В моем приложении я хочу перенести идентификатор Elmah на пользовательскую страницу ошибок, поскольку я предоставлю ссылку, которая позволит пользователю специально сообщать об этом в случае повторной ошибки (по их мнению).

Теперь я прочитал похожие вопросы здесь, и они предлагают добавить следующий код (или аналогичный) в файл Global.asax.cs:

void ErrorLog_Logged(object sender, ErrorLoggedEventArgs args)
{
    string sessionId = Session.SessionID;
    Session["ElmahId_" + sessionId] = args.Entry.Id;
}

Это то, что я использую намомент, с SessionID, обеспечивающим дополнительную гибкость в создании уникального хранимого объекта Session.Тем не менее, это может по-прежнему вызывать проблемы, если в одно и то же время (более) происходит несколько ошибок.

Вместо этого я решил поработать над своим собственным атрибутом HandleErrorAttribute, который выглядит примерно так:

public class ElmahHandleErrorAttribute : FilterAttribute, IExceptionFilter
{
    public void OnException(ExceptionContext filterContext)
    {
        if (filterContext == null)
            throw new ArgumentNullException("filterContext");

        if (filterContext.IsChildAction && (!filterContext.ExceptionHandled
            && filterContext.HttpContext.IsCustomErrorEnabled))
        {
            Elmah.ErrorSignal.FromCurrentContext().Raise(filterContext.Exception);

            // get error id here
            string errorId = null;

            string areaName = (String)filterContext.RouteData.Values["area"];
            string controllerName = (String)filterContext.RouteData.Values["controller"];
            string actionName = (String)filterContext.RouteData.Values["action"];

            var model = new ErrorDetail
            {
                Area = areaName,
                Controller = controllerName,
                Action = actionName,
                ErrorId = errorId,
                Exception = filterContext.Exception
            };

            ViewResult result = new ViewResult
            {
                ViewName = "Error",,
                ViewData = new ViewDataDictionary<ErrorDetail>(model),
                TempData = filterContext.Controller.TempData
            };

            filterContext.Result = result;
            filterContext.ExceptionHandled = true;
            filterContext.HttpContext.Response.Clear();
            filterContext.HttpContext.Response.TrySkipIisCustomErrors = true;
        }
    }
}

где ErrorDetail - это пользовательская модель, которая просто имеет открытые свойства, которые задаются здесь как строки.Затем эти данные можно быстро отобразить в модели для администраторов, а errorId можно использовать для создания ссылки «Сообщить об ошибке».

Так что мой вопрос: знает ли кто-нибудь способ получения идентификаторапосле строки

Elmah.ErrorSignal.FromCurrentContext().Raise(filterContext.Exception)

без использования события Logged в global.asax.cs?

Любые мысли приветствуются.

Ответы [ 4 ]

7 голосов
/ 26 октября 2011

После прочтения комментариев Дюпина кажется логичным, что это не совсем возможно. Я попытался покопаться в исходном коде Elmah и нашел пару альтернатив, которыми стоит поделиться.

Очевидная альтернатива - придерживаться моего первоначального варианта использования события Logged:

void ErrorLog_Logged(object sender, ErrorLoggedEventArgs args)
{
    string sessionId = Session.SessionID;
    Session["ElmahId_" + sessionId] = args.Entry.Id;
}

Для более прямого решения можно вручную зарегистрировать ошибку следующим образом:

string errorId = Elmah.ErrorLog.GetDefault(HttpContext.Current)
    .Log(new Elmah.Error(filterContext.Exception));

Однако использование этого подхода не затронет ваши фильтры или почтовый модуль и т. Д.

Подумав немного и немного подумав, я нашел новый компромисс. Все еще использую зарегистрированное событие, но я нашел способ создать новый уникальный ключ, который можно передать представлению, добавив мои собственные данные в исключение.

string loggingKey = "ElmahId_" + Guid.NewGuid().ToString();
filterContext.Exception.Data.Add("LoggingKey", loggingKey);

Таким образом, я могу передать исключение в моей модели представления, у которой есть это значение ключа в Сбор данных. Зарегистрированное событие будет изменено на что-то вроде этого:

void ErrorLog_Logged(object sender, ErrorLoggedEventArgs args)
{
    string key = args.Entry.Error.Exception.Data["LoggingKey"].ToString();
    Session[key] = args.Entry.Id;
}

Затем в представлении я получаю ключ от модели, чтобы затем извлечь идентификатор из коллекции сеансов.

2 голосов
/ 26 октября 2011

Может быть, не очень полезно, но я подозреваю, что вы не можете получить идентификатор ошибки в этот момент, и вам нужно будет использовать зарегистрированное событие.

Когда вы звоните

Elmah.ErrorSignal.FromCurrentContext().Raise(filterContext.Exception)

ВыПоднимаешь ошибку.В зависимости от того, как вы настроили ELMAH, вы можете регистрировать ошибку или просто отправить электронное письмо или твит.

Нет прямой связи между возникшей ошибкой и идентификатором.Это будет происходить только с ведением журнала, который, если вы чувствуете себя смешно, вы можете делать в нескольких местах и ​​создавать несколько идентификаторов.

1 голос
/ 03 мая 2012

http://code.google.com/p/elmah/issues/detail?id=148#c3 - идентичный запрос и предлагаемый патч на сайте проекта Elmah

0 голосов
/ 08 декабря 2012

Приведенное выше решение работает только при наличии объекта Session (сценарий веб-сайта). Нам нужно, чтобы он работал в Azure WorkerRole или в настройке типа консольного / настольного приложения. Это решение также будет работать для Интернета и сэкономить память сеанса. Не существует идеального решения, но для того, чтобы мы смогли зарегистрировать ошибку и извлечь сохраненный идентификатор, а затем отправить электронное письмо, необходимо:

  1. Сохранить ошибку с помощью ErrorLog.Log (ошибка) (см .: Использование ELMAH в консольном приложении )
  2. Поднять ошибку, пропуская ведение журнала (SQL или иное)

Для второй части мы использовали приведенную здесь реализацию ElmahExtension: https://stackoverflow.com/a/2473580/476400

и удалил следующие строки, добавив запись в лог:

(ErrorLog as IHttpModule).Init(httpApplication);
errorFilter.HookFiltering(ErrorLog);  //removed!

Весь вызов нашего клиентского кода выглядит следующим образом:

ErrorLog errorLog = ErrorLog.GetDefault(null);
errorLog.ApplicationName = "YourAppName";
Error error = new Error(ex);
string errorResult = errorLog.Log(error);
Guid errorId = new Guid(errorResult);

ex.LogToElmah(); //this is just going to send the email

Возможно, вы захотите вызвать этот метод расширения как-нибудь еще, например, RaiseToElmahNoStorage (), или что-то, указывающее, что он пропускает компонент хранения.

...