在调用.Raise()后获取Elmah中的错误ID

时间:2011-10-25 20:11:58

标签: asp.net-mvc elmah

我正在研究一个MVC3应用程序,我正在使用Elmah来处理我的错误记录。我在我的应用程序中想要的是将Elmah Id带到自定义错误页面,因为我将提供一个链接,允许用户在重复错误(他们认为)的情况下专门报告它。

现在,我在这里阅读了类似的问题,他们建议在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可用于创建“报告错误”链接。

所以我的问题是有没有人知道在行后获取Id的方法

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

不使用global.asax.cs中的Logged事件?

非常感谢任何想法。

4 个答案:

答案 0 :(得分:7)

在阅读了杜宾的评论之后,这似乎是不合逻辑的。我尝试挖掘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);

这样我可以在我的视图模型中传递异常,该模型在Data集合中具有此键值。记录的事件将更改为以下内容:

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

然后在视图中,我从模型中获取密钥,然后从Session集合中提取Id。

答案 1 :(得分:2)

也许不是很有帮助,但我怀疑你不能在那时获得错误ID,你需要使用记录的事件。

致电时

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

你只是提出错误。根据您配置ELMAH的方式,您可能正在记录错误,或者您可能只是发送电子邮件或推文。

引发的错误与ID之间没有直接联系。这只会带来日志记录,如果你感觉好笑,你可能会在多个地方做,所以创建多个ID。

答案 2 :(得分:1)

http://code.google.com/p/elmah/issues/detail?id=148#c3是一个相同的请求和Elmah项目网站上提出的补丁

答案 3 :(得分:0)

上述解决方案仅在存在会话对象(网站方案)时才有效。我们需要它在Azure WorkerRole或控制台/桌面应用程序类型设置中工作。此解决方案也适用于Web并保存一些会话内存。没有一个完美的解决方案,但有一个能够记录错误并检索存储的ID并启动电子邮件的工具是:

  1. 使用ErrorLog.Log(错误)存储错误(请参阅:Using ELMAH in a console application
  2. 提高跳过日志记录(SQL或其他)
  3. 的错误

    对于第二部分,我们使用了这里给出的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(),或者某些东西,以表明它正在跳过存储组件。