我正在研究一个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事件?
非常感谢任何想法。
答案 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并启动电子邮件的工具是:
对于第二部分,我们使用了这里给出的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(),或者某些东西,以表明它正在跳过存储组件。