我正在使用 MVC5 构建一个新的Web应用程序,我需要以下内容:
Id
记录我正在努力阅读)我发现了很多关于HandleErrorAttribute
的信息,但没有一个信息允许在错误中添加具体细节,我也找到了try catch
的信息对于服务器,aproach 太重。
现在,我有:
控制器:
public partial class HomeController : Controller
{
private static Logger logger = LogManager.GetCurrentClassLogger();
public virtual ActionResult Index()
{
try
{
return View();
}
catch (Exception e)
{
logger.Error("Error in Index: " + e);
return MVC.Error.Index("Error in Home Controller");
}
}
}
我发现这个扩展的HandleErrorAttribute
似乎已经完成,但却没有做我需要的一切:
private bool IsAjax(ExceptionContext filterContext)
{
return filterContext.HttpContext.Request.Headers["X-Requested-With"] == "XMLHttpRequest";
}
public override void OnException(ExceptionContext filterContext)
{
if (filterContext.ExceptionHandled || !filterContext.HttpContext.IsCustomErrorEnabled)
{
return;
}
// if the request is AJAX return JSON else view.
if (IsAjax(filterContext))
{
//Because its a exception raised after ajax invocation
//Lets return Json
filterContext.Result = new JsonResult(){Data=filterContext.Exception.Message,
JsonRequestBehavior=JsonRequestBehavior.AllowGet};
filterContext.ExceptionHandled = true;
filterContext.HttpContext.Response.Clear();
}
else
{
//Normal Exception
//So let it handle by its default ways.
base.OnException(filterContext);
}
// Write error logging code here if you wish.
//if want to get different of the request
//var currentController = (string)filterContext.RouteData.Values["controller"];
//var currentActionName = (string)filterContext.RouteData.Values["action"];
}
答案 0 :(得分:4)
您的要求最适合Elmah
。用于记录错误的非常好的插件。
ELMAH
代表错误记录模块和处理程序
ELMAH
提供了如此高度的可插拔性,即使安装ELMAH也不需要编译您的应用程序。
的博客的参考资料ELMAH(错误记录模块和处理程序)是一个完全可插拔的应用程序范围的错误记录工具。它可以动态添加到正在运行的ASP.NET Web应用程序,甚至是机器上的所有ASP.NET Web应用程序,而无需重新编译或重新部署。
只需将ELMAH的二进制文件复制到应用程序的bin文件夹中,然后编辑 web.config 文件即可。那就是它!
您需要在web.config中添加以下内容,并进行以下链接中描述的其他更改。
<sectionGroup name="elmah">
<section name="security" requirePermission="false" type="Elmah.SecuritySectionHandler, Elmah" />
<section name="errorLog" requirePermission="false" type="Elmah.ErrorLogSectionHandler, Elmah" />
<section name="errorMail" requirePermission="false" type="Elmah.ErrorMailSectionHandler, Elmah" />
<section name="errorFilter" requirePermission="false" type="Elmah.ErrorFilterSectionHandler, Elmah" />
</sectionGroup>
例如,设置邮件帐户。
<configuration>
<configSections>
<sectionGroup name="elmah">
<section name="errorLog" requirePermission="false" type="Elmah.ErrorLogSectionHandler, Elmah"/>
<section name="errorMail" requirePermission="false" type="Elmah.ErrorMailSectionHandler, Elmah"/>
<section name="errorFilter" requirePermission="false" type="Elmah.ErrorFilterSectionHandler, Elmah"/>
</sectionGroup>
</configSections>
<elmah>
<errorMail from="test@test.com" to="test@test.com"
subject="Application Exception" async="false"
smtpPort="25" smtpServer="***"
userName="***" password="***">
</errorMail>
</elmah>
<system.web>
<customErrors mode="RemoteOnly" defaultRedirect="CustomError.aspx">
<error statusCode="403" redirect="NotAuthorized.aspx" />
<!--<error statusCode="404" redirect="FileNotFound.htm" />-->
</customErrors>
<httpHandlers>
<remove verb="*" path="*.asmx"/>
<add verb="*" path="*.asmx" validate="false" type="System.Web.Script.Services.ScriptHandlerFactory, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>
<add verb="*" path="*_AppService.axd" validate="false" type="System.Web.Script.Services.ScriptHandlerFactory, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>
<add verb="GET,HEAD" path="ScriptResource.axd" type="System.Web.Handlers.ScriptResourceHandler, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" validate="false"/>
<add verb="POST,GET,HEAD" path="elmah.axd" type="Elmah.ErrorLogPageFactory, Elmah" />
</httpHandlers>
<httpModules>
<add name="ScriptModule" type="System.Web.Handlers.ScriptModule, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>
<add name="ErrorLog" type="Elmah.ErrorLogModule, Elmah"/>
<add name="ErrorMail" type="Elmah.ErrorMailModule, Elmah" />
</httpModules>
</system.web>
</configuration>
以下是一些很好的参考链接(包含对项目安装ELMAH的详细参考)供您参考。
https://msdn.microsoft.com/en-us/library/aa479332.aspx
https://code.google.com/p/elmah/wiki/MVC
<强>更新强>
添加详细的自定义信息(例如我尝试阅读的记录的ID)
您可以构建自己的自定义异常,该异常派生自Exception。
public class MyException : Exception
{
public MyException(string message, Exception ex) : base(ex.Message, ex)
{
}
}
然后像
一样使用它public virtual ActionResult Index()
{
try
{
return View();
}
catch (Exception e)
{
throw new MyException("detailed exception", e);
}
}
以这种方式将主要异常包含在myexception中,您可以添加详细的自定义异常消息。
返回查看给用户的自定义消息
你只需要添加
<system.web>
<customErrors mode="On">
</customErrors>
<sytem.web>
并在Error.cshtml
文件夹中添加~/View/Shared
然后,每当遇到异常时,它将在view / shared文件夹中找到Error.cshtml并呈现内容。所以你可以在那里呈现自定义信息。
答案 1 :(得分:3)
使用Elmah,其他人也建议使用。我是,并且没有回头!
它符合您的所有要求:
关于自定义代码(上面的第二点),AFAIK有两种选择:
<强> 1。创建自定义错误日志实现。
这并不困难。这就是我做的!
覆盖默认错误日志数据存储。例如,获取SQL Server数据存储:
In Web.config
<elmah>
<errorLog type="Elmah.SqlErrorLog, Elmah" connectionStringName="myCn" applicationName="myAppName" />
</elmah>
接下来,创建一个类“MySQLServerErrorLog”并从Elmah.ErrorLog派生
然后需要的是覆盖 Log()方法。
public override string Log(Error error)
{
// You have access to all the error details - joy!
= error.HostName,
= error.Type,
= error.Message,
= error.StatusCode
= error.User,
= error.Source,
// Call the base implementation
}
在Web.config中,将默认(上面)条目替换为您的实现:
<elmah>
<errorLog type="myProjectName.MySQLServerErrorLog, myProjectName" />
</elmah>
<强> 2。您可以通过编程方式记录错误
使用ErrorSignal类,您可以记录错误,而不必引发未处理的异常。
语法: ErrorSignal.FromCurrentContext()。Raise(new NotSupportedException());
示例:自定义异常
var customException = new Exception("My error", new NotSupportedException());
ErrorSignal.FromCurrentContext().Raise(customException);
这使您可以选择使用自定义逻辑以编程方式记录您需要的任何内容。
我已经为我的Elmah实例编写了将错误记录到Azure云存储表和Blob(错误堆栈跟踪详细信息)的功能。
在使用Elmah之前,我已经为MVC编写了自己的异常处理机制,它使用了HandleErrorAttribute和Application_Error(在Global.asax中)。它有效,但IMO太笨重了。答案 2 :(得分:2)
如果是我,我会创建自己的异常处理属性,它将所需行为添加到HandleErrorAttribute的基本实现中。
我过去有过很好的结果,因为他们具有属性&#34;指向&#34;感兴趣的请求的各个部分(我想你想要记录特定细节的位置) - 所以你可以使用这些标识符将请求拉到碎片上使用反射:
CustomHandleErrorAttribute(["id", "name", "model.lastUpdatedDate"])
我已使用此方法来保护控制器操作(确保客户正在请求他们允许请求的内容) - 例如父母要求他们的孩子,而不是其他人的孩子。
或者,您可以设置一个配置,以便链接&#34;链接&#34;处理程序在一起 - 所以很多小的处理程序,都在做非常具体的位,都在处理相同的请求并请求指针(如上所述):
ChainedErrorHandling("emailAndLogFile", ["id", "name", "model.lastUpdatedDate"])
where&#34; emailAndLogFile&#34;创建一个从FilterAttribute继承的错误处理程序链,其中最后一个是标准的MVC HandleErrorAttribute。
但到目前为止,最简单的方法是前两种方法。
HTH
EDITED TO ADD:继承自定义错误处理的示例:
public class CustomErrorAttribute : HandleErrorAttribute
{
public CustomErrorAttribute(string[] requestPropertiesToLog)
{
this.requestPropertiesToLog = requestPropertiesToLog;
}
public string[] requestPropertiesToLog { get; set; }
public override void OnException(ExceptionContext filterContext)
{
var requestDetails = this.GetPropertiesFromRequest(filterContext);
// do custom logging / handling
LogExceptionToEmail(requestDetails, filterContext);
LogExceptionToFile(requestDetails, filterContext);
LogExceptionToElseWhere(requestDetails, filterContext);// you get the idea
// even better - you could use DI (as you're in MVC at this point) to resolve the custom logging and log from there.
//var logger = DependencyResolver.Current.GetService<IMyCustomErrorLoggingHandler>();
// logger.HandleException(requestDetails, filterContext);
// then let the base error handling do it's thang.
base.OnException(filterContext);
}
private IEnumerable<KeyValuePair<string, string>> GetPropertiesFromRequest(ExceptionContext filterContext)
{
// in requestContext is the queryString, form, user, route data - cherry pick bits out using the this.requestPropertiesToLog and some simple mechanism you like
var requestContext = filterContext.RequestContext;
var qs = requestContext.HttpContext.Request.QueryString;
var form = requestContext.HttpContext.Request.Form;
var user = requestContext.HttpContext.User;
var routeDataOfActionThatThrew = requestContext.RouteData;
yield break;// just break as I'm not implementing it.
}
private void LogExceptionToEmail(IEnumerable<KeyValuePair<string, string>> requestDetails, ExceptionContext filterContext)
{
// send emails here
}
private void LogExceptionToFile(IEnumerable<KeyValuePair<string, string>> requestDetails, ExceptionContext filterContext)
{
// log to files
}
private void LogExceptionToElseWhere(IEnumerable<KeyValuePair<string, string>> requestDetails, ExceptionContext filterContext)
{
// send cash to me via paypal everytime you get an exception ;)
}
}
在控制器操作上,您可以添加以下内容:
[CustomErrorAttribute(new[] { "formProperty1", "formProperty2" })]
public ActionResult Index(){
return View();
}
答案 3 :(得分:1)
首先,您可以定义一个过滤器属性,并且可以在global.asax
中的MVC应用程序中在启动时注册它,这样您就可以捕获在调用操作时发生的任何类型的错误。
注意:依赖性解析是可更改的。我正在使用Castle Windsor这个故事。您可以解决自己的IOC容器的依赖关系。例如,ILogger依赖。我在动作调用时用于此属性注入。 Windsor Action Invoker
对于示例过滤器:
public class ExceptionHandling : FilterAttribute, IExceptionFilter
{
public ILogger Logger { get; set; }
public void OnException(ExceptionContext filterContext)
{
Logger.Log("On Exception !", LogType.Debug, filterContext.Exception);
if (filterContext.Exception is UnauthorizedAccessException)
{
filterContext.Result = UnauthorizedAccessExceptionResult(filterContext);
}
else if (filterContext.Exception is BusinessException)
{
filterContext.Result = BusinessExceptionResult(filterContext);
}
else
{
// Unhandled Exception
Logger.Log("Unhandled Exception ", LogType.Error, filterContext.Exception);
filterContext.Result = UnhandledExceptionResult(filterContext);
}
}
}
这样你可以捕捉到一切。
所以:
private static ActionResult UnauthorizedAccessExceptionResult(ExceptionContext filterContext)
{
// Send email, fire event, add error messages
// for example handle error messages
// You can seperate the behaviour by: if (filterContext.HttpContext.Request.IsAjaxRequest())
filterContext.ExceptionHandled = true;
filterContext.HttpContext.Response.TrySkipIisCustomErrors = true;
filterContext.Controller.TempData.Add(MessageType.Danger.ToString(), filterContext.Exception.Message);
// So you can show messages using with TempData["Key"] on your action or views
var lRoutes = new RouteValueDictionary(
new
{
action = filterContext.RouteData.Values["action"],
controller = filterContext.RouteData.Values["controller"]
});
return new RedirectToRouteResult(lRoutes);
}
在Global.asax中:
protected void Application_Start()
{
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
}
一个FilterConfig:
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
filters.Add(new ExceptionHandling());
}
BusinessException:
public class BusinessException : Exception, ISerializable
{
public BusinessException(string message)
: base(message)
{
// Add implemenation (if required)
}
}
因此,您可以使用OnException
ExceptionHandling
班级的异常消息filterContext.Exception.Message
您应该在违反控制逻辑之后对此操作使用BusinessException
:throw new BusinessException("Message")
。
答案 4 :(得分:0)
为什么不创建包含所需错误信息的模型,并在需要时将数据绑定到模型?它还允许您从中创建/返回视图
答案 5 :(得分:-1)
您可以使用包含所需信息(id,tablesname等)的客户异常来捕获特殊信息的全局错误。
在HandleErrorAttribute中你只是&#34;只有&#34;有httpContext / ExceptionContext和其他静态信息。