我在部署在共享主机上的ASP.NET MVC应用程序上遇到自定义错误问题。我创建了一个ErrorController并将以下代码添加到Global.asax以捕获未处理的异常,记录它们,然后将控制转移到ErrorController以显示自定义错误。此代码取自here:
protected void Application_Error(object sender, EventArgs e)
{
Exception ex = Server.GetLastError();
Response.Clear();
HttpException httpEx = ex as HttpException;
RouteData routeData = new RouteData();
routeData.Values.Add("controller", "Error");
if (httpEx == null)
{
routeData.Values.Add("action", "Index");
}
else
{
switch (httpEx.GetHttpCode())
{
case 404:
routeData.Values.Add("action", "HttpError404");
break;
case 500:
routeData.Values.Add("action", "HttpError500");
break;
case 503:
routeData.Values.Add("action", "HttpError503");
break;
default:
routeData.Values.Add("action", "Index");
break;
}
}
ExceptionLogger.LogException(ex); // <- This is working. Errors get logged
routeData.Values.Add("error", ex);
Server.ClearError();
IController controller = new ErrorController();
// The next line doesn't seem to be working
controller.Execute(new RequestContext(new HttpContextWrapper(Context), routeData));
}
Application_Error肯定会被激活,因为日志记录工作正常,但我没有显示自定义错误页面,而是获得Go Daddy泛型。从博客文章的标题中取出上面的代码,我注意到它使用了MVC框架的Release Candidate 2。在1.0中有什么变化使最后一行代码不起作用?像往常一样works great on my machine。
任何建议都将不胜感激。
编辑:忘记提及我已经尝试了Web.config(Off,On和RemoteOnly)中的customErrors模式的所有3种可能性。无论此设置如何,结果都相同。
编辑2:我还在Controller类中使用和不使用[HandleError]装饰时尝试过它。
更新:我已经找到并修复了404。 Go Daddy的托管控制中心的“设置”面板中有一部分可以控制404行为,默认情况下是显示其通用页面,显然这会覆盖任何Web.config设置。所以我的自定义404页面现在按预期显示。但是,500和503仍然无法正常工作。如果Sql Server抛出异常,我在HomeController中有代码来获取内容的静态文本版本,如下所示:
public ActionResult Index()
{
CcmDataClassesDataContext dc = new CcmDataClassesDataContext();
// This might generate an exception which will be handled in the OnException override
HomeContent hc = dc.HomeContents.GetCurrentContent();
ViewData["bodyId"] = "home";
return View(hc);
}
protected override void OnException(ExceptionContext filterContext)
{
// Only concerned here with SqlExceptions so an HTTP 503 message can
// be displayed in the Home View. All others will bubble up to the
// Global.asax.cs and be handled/logged there.
System.Data.SqlClient.SqlException sqlEx =
filterContext.Exception as System.Data.SqlClient.SqlException;
if (sqlEx != null)
{
try
{
ExceptionLogger.LogException(sqlEx);
}
catch
{
// couldn't log exception, continue without crashing
}
ViewData["bodyId"] = "home";
filterContext.ExceptionHandled = true;
HomeContent hc = ContentHelper.GetStaticContent();
if (hc == null)
{
// Couldn't get static content. Display friendly message on Home View.
Response.StatusCode = 503;
this.View("ContentError").ExecuteResult(this.ControllerContext);
}
else
{
// Pass the static content to the regular Home View
this.View("Index", hc).ExecuteResult(this.ControllerContext);
}
}
}
以下是尝试获取静态内容的代码:
public static HomeContent GetStaticContent()
{
HomeContent hc;
try
{
string path = Configuration.CcmConfigSection.Config.Content.PathToStaticContent;
string fileText = File.ReadAllText(path);
string regex = @"^[^#]([^\r\n]*)";
MatchCollection matches = Regex.Matches(fileText, regex, RegexOptions.Multiline);
hc = new HomeContent
{
ID = Convert.ToInt32(matches[0].Value),
Title = matches[1].Value,
DateAdded = DateTime.Parse(matches[2].Value),
Body = matches[3].Value,
IsCurrent = true
};
}
catch (Exception ex)
{
try
{
ExceptionLogger.LogException(ex);
}
catch
{
// couldn't log exception, continue without crashing
}
hc = null;
}
return hc;
}
我已经验证过,如果我更改连接字符串以生成SqlException,则代码会正确记录错误,然后抓取并显示静态内容。但是,如果我还在Web.config中更改静态文本文件的路径来测试主视图的503版本,那么我得到的是一个除“服务不可用”之外的页面。而已。没有具有网站外观的自定义503消息。
是否有人对代码的改进有任何建议可能有所帮助?将不同的标题添加到HttpResponse会有帮助吗?还是Go Daddy狠狠地劫持了503s?
答案 0 :(得分:29)
我找到了解决方案,而且非常简单。事实证明问题实际上是在IIS7中。在Visual Studio中调试此问题时,我看到了之前没有注意到的HttpResponse对象的属性:
public bool TrySkipIisCustomErrors { get; set; }
这引导我到最近的搜索引擎,great blog post by Rick Strahl和另一个angrypets.com以及this question here on SO。这些链接比我能更好地解释了血腥细节,但Rick的帖子引用它很好地抓住了它:
这里出现了真正的混乱,因为错误被困住了 ASP.NET,但最终仍然由IIS处理,看看 500状态代码并返回库存IIS错误页面。
似乎此行为特定于集成模式下的IIS7。来自msdn:
在IIS 7.0中以经典模式运行TrySkipIisCustomErrors时 属性默认值为true。在集成模式下运行时, TrySkipIisCustomErrors属性的默认值为false。
基本上我所要做的就是在任何将Response.TrySkipIisCustomErrors = true;
设置为500或503的代码之后立即添加Response.StatusCode
,现在所有内容都按设计运行。
答案 1 :(得分:0)
我在GoDaddy上托管一个ASP.NET MVC网站,并且还遇到了处理自定义错误页面的问题。通过反复试验,我发现GoDaddy拦截了HTTP级别的错误。
例如,任何返回HTTP状态代码为404的页面都会导致GoDaddy的自定义错误页面接管。最终我将自定义错误页面更改为200状态,404相关问题消失了。我的HTML是相同的,只是需要更改的HTTP状态。
我承认从未尝试过对503状态响应做同样的事情,但同样的缓解措施可能有效。如果您从返回503状态更改为返回200状态,问题是否会消失?
请注意,如果您执行此解决方法,您将希望阻止搜索引擎索引您的错误页面,一旦返回200状态将从常规页面无法区分(从搜索引擎的角度来看)。因此,请务必添加META ROBOTS标记,以防止对错误页面编制索引,例如:
<META NAME="ROBOTS" CONTENT="NOINDEX">
这种方法的缺点可能是您的网页可能会从Google中删除,这绝对不是一件好事!
更新:因此,此外,您还可以检测用户代理是否是抓取工具,如果是抓取工具返回503,如果它不是抓取工具,则返回200。有关如何检测抓取工具的信息,请参阅this blog post。是的,我知道向抓取工具和用户返回不同的内容是SEO禁忌,但我已经在几个网站上做到了这一点,到目前为止没有任何不良影响,所以我不确定是多少问题。
如果任何奇怪的爬行者穿过僵尸探测器,那么这两种方法(META ROBOTS和机器人探测)可能是您最好的选择。