すべてのエラー (HandleError 属性を持つコントローラーで発生するエラーだけでなく) を処理する maxlego と同様のことを行います。
私の MvcApplication クラス (global.asax.cs 内) には次のものがあります。
public class MvcApplication : HttpApplication
{
// usual stuff here...
protected void Application_Error(object sender, EventArgs e)
{
Server.HandleError(((MvcApplication)sender).Context);
}
}
上記のコードは、便利なものの MVC ライブラリの拡張メソッドを使用しています。これにより、エラー処理属性、customErrors 構成、またはカスタム フィルターは必要ありません。代わりに、拡張メソッドはエラーの詳細をログに記録し、次のいずれかの適切なビューを呼び出します。
- アクセスが拒否されました
- 見つかりません
- 内部サーバーエラー
これを機能させるための拡張メソッド コードは次のとおりです。
public static class HttpServerUtilityExtensions
{
private static readonly Logger Logger = LogManager.GetCurrentClassLogger();
public static void HandleError(this HttpServerUtility server, HttpContext httpContext)
{
var currentController = " ";
var currentAction = " ";
var currentRouteData = RouteTable.Routes.GetRouteData(new HttpContextWrapper(httpContext));
if (currentRouteData != null)
{
if (currentRouteData.Values["controller"] != null && !String.IsNullOrEmpty(currentRouteData.Values["controller"].ToString()))
currentController = currentRouteData.Values["controller"].ToString();
if (currentRouteData.Values["action"] != null && !String.IsNullOrEmpty(currentRouteData.Values["action"].ToString()))
currentAction = currentRouteData.Values["action"].ToString();
}
var exception = server.GetLastError();
Logger.ErrorException(exception.Message, exception);
var controller = DependencyResolver.Current.GetService<ErrorController>();
var routeData = new RouteData();
var action = "InternalServerError";
if (exception is HttpException)
{
var httpEx = exception as HttpException;
switch (httpEx.GetHttpCode())
{
case 404:
action = "NotFound";
break;
case 401:
action = "AccessDenied";
break;
}
}
httpContext.ClearError();
httpContext.Response.Clear();
httpContext.Response.StatusCode = exception is HttpException ? ((HttpException)exception).GetHttpCode() : 500;
httpContext.Response.TrySkipIisCustomErrors = true;
routeData.Values["controller"] = "Error";
routeData.Values["action"] = action;
controller.ViewData.Model = new HandleErrorInfo(exception, currentController, currentAction);
((IController)controller).Execute(new RequestContext(new HttpContextWrapper(httpContext), routeData));
}
}
上記では、エラーの詳細を記録するために NLog を使用していますが、他の何かをサポートするように簡単に変更できます。また、このメソッドは、ErrorController を解決するときに IoC コンテナーを尊重します。