カスタムHandleErrorAttributeを使用してカスタム例外のみを処理するMVC4アプリがあります。デフォルトの404およびその他の500以外のエラーページをインターセプトして、より魅力的なものに置き換えたいと思います。そのために、Web.configに以下を追加しました。
<system.web>
<customErrors mode="On" defaultRedirect="~/Error/Index" />
...
</ system.web>
Indexメソッドと対応するビューを備えたエラーコントローラーがありますが、それでもデフォルトの404エラーページが表示されます。また、defaultRedirect
を静的なhtmlファイルに設定してみました。 <customErrors>
内に404に固有のエラー処理を追加しようとしましたが、プログラムでルートを変更しようとしましたが、すべて結果がありませんでした。何が足りないのですか? ASPがデフォルトのエラー処理を無視するのはなぜですか?
注:<customErrors mode="On"
を使用しても、CustomHandleErrorAttributeをローカルでテストできないことに以前気づきました。ただし、開発ボックスからサーバーにアクセスすると機能します...それが関連しているかどうかはわかりません。 この男 同じ問題がありました。
これはうまくいくはずです:
1。Web.Config
<customErrors mode="On"
defaultRedirect="~/Views/Shared/Error.cshtml">
<error statusCode="403"
redirect="~/Views/Shared/UnauthorizedAccess.cshtml" />
<error statusCode="404"
redirect="~/Views/Shared/FileNotFound.cshtml" />
</customErrors>
2。次のようにFilterConfigクラスにグローバルアクションフィルターとしてHandleErrorAttributeを登録しました
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
filters.Add(new CustomHandleErrorAttribute());
filters.Add(new AuthorizeAttribute());
}
それでもうまくいかない場合は、Global.asaxで次のようなステータスコードを確認して、応答を転送するようにしてください。少なくとも機能する必要があります。
void Application_EndRequest(object sender, EventArgs e)
{
if (Response.StatusCode == 401)
{
Response.ClearContent();
Server.Transfer("~/Views/Shared/UnauthorizedAccess.cshtml");
}
}
私は少し話題から外れます。これを説明するのは少し重要だと思いました。
上記の強調表示された部分に注意を払う場合。アクションフィルターの順序を指定しました。これは基本的にアクションフィルターの実行順序を説明します。これは、コントローラー/アクションメソッドに複数のアクションフィルターが実装されている場合の状況です。
この画像は、2つのアクションフィルターがあるとしましょう。 OnActionExecution
は優先度で実行を開始し、OnActionExecuted
は下から上に開始します。つまり、OnActionExecuted
の場合、最も高い順序のアクションフィルターが最初に実行され、OnActionExecuting
の場合、最も低い順序のアクションフィルターが最初に実行されます。以下の例
public class Filter1 : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
//実行はここから始まります-1
base.OnActionExecuting(filterContext);
}
public override void OnActionExecuted(ActionExecutedContext filterContext)
{
//実行はここに移動します-5
base.OnActionExecuted(filterContext);
}
}
public class Filter2 : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
//実行はここに移動します-2
base.OnActionExecuting(filterContext);
}
public override void OnActionExecuted(ActionExecutedContext filterContext)
{
//実行はここに移動します-4
base.OnActionExecuted(filterContext);
}
}
[HandleError]
public class HomeController : Controller
{
[Filter1(Order = 1)]
[Filter2(Order = 2)]
public ActionResult Index()
{
//実行はここに移動します-3
ViewData["Message"] = "Welcome to ASP.NET MVC!";
return View();
}
}
MVCフレームワーク内にはさまざまなタイプのフィルターがあることをすでにご存知かもしれません。それらは以下にリストされています。
承認フィルター
アクションフィルター
応答/結果フィルター
例外フィルター
各フィルター内で、Orderプロパティを指定できます。これは基本的に、アクションフィルターの実行順序を説明します。
これは私にとってはうまくいきます。これは非常に簡単で、Web.Configの変更を検討したり、Global.asaxファイルにアクションフィルターを登録したりする必要はありません。
oK。したがって、最初に単純なアクションフィルターを作成しています。これは、Ajaxおよび非Ajaxリクエストを処理します。
public class MyCustomErrorAttribute : HandleErrorAttribute
{
public override void OnException(ExceptionContext filterContext)
{
filterContext.ExceptionHandled = true;
var debugModeMsg = filterContext.HttpContext.IsDebuggingEnabled
? filterContext.Exception.Message +
"\n" +
filterContext.Exception.StackTrace
: "Your error message";
//これは、Ajaxリクエストを処理する必要がある場合です
if (filterContext.HttpContext.Request.IsAjaxRequest())
{
filterContext.Result = new JsonResult
{
JsonRequestBehavior = JsonRequestBehavior.AllowGet,
Data = new
{
error = true,
message = debugModeMsg
}
};
}
//これは、Ajax以外のリクエストを処理する場合です
else
{
var routeData = new RouteData();
routeData.Values["controller"] = "Error";
routeData.Values["action"] = "Error";
routeData.DataTokens["area"] = "app";
routeData.Values["exception"] = debugModeMsg;
IController errorsController = new ErrorController();
var exception = HttpContext.Current.Server.GetLastError();
var httpException = exception as HttpException;
if (httpException != null)
{
Response.StatusCode = httpException.GetHttpCode();
switch (System.Web.HttpContext.Current.Response.StatusCode)
{
case 404:
routeData.Values["action"] = "Http404";
break;
}
}
var rc = new RequestContext
(
new HttpContextWrapper(HttpContext.Current),
routeData
);
errorsController.Execute(rc);
}
base.OnException(filterContext);
}
}
これで、このアクションフィルターをコントローラーとアクションのみに実装できます。例:
これがお役に立てば幸いです。
この問題を調査した後、私の知識を共有したいと思います。私の発言を改善するのに役立つコメントは大歓迎です。
ASP.NET MVCには、次の順序でHTTP要求を処理する3つのレイヤーがあります(応答は逆の順序で転送されます)。
IIS(HTTPレイヤー)
ASP.NET(サーバーレイヤー)
コントローラー(MVCレイヤー)
これらのすべてのレイヤーにはエラー処理がありますが、各レイヤーの処理は異なります。 IISから始めます。
IISがエラーを処理する方法の最も簡単な例は、ブラウザーを使用して、サーバーから存在しない.htmlファイルを要求することです。アドレスは次のようになります。
http:// localhost:50123/this_does_not_exist.html
ブラウザタブのタイトルに注意してください。例:IIS 10.0詳細エラー-404.0-見つかりません。
IISがHTTP要求を受信すると、URLが.aspxで終わる場合、この拡張子を処理するように登録されているため、ASP.NETに転送します。ASP.NETが処理する方法の最も簡単な例エラーは、ブラウザを使用して、サーバーに存在しない.aspxファイルを要求することです。アドレスは次のようになります。
http:// localhost:50123/this_does_not_exist.aspx
ページの下部に表示されるバージョン情報に注意してください。これは、ASP.NETのバージョンを示しています。
customErrorsタグは、もともとASP.NET用に作成されました。応答がASP.NET内部コードによって作成された場合にのみのみ効果があります。これは、アプリケーションコードから作成された応答には影響しないことを意味します。さらに、ASP.NETによって返される応答にコンテンツがなく、エラーステータスコード(4xxまたは5xx)がある場合、IISは、ステータスコードに従って応答を置き換えます。いくつかの例を提供します。
Page_Load メソッドにResponse.StatusCode = 404
が含まれている場合、コンテンツは正常に表示されます。追加のコードResponse.SuppressContent = true
が追加されると、IISが介入し、「this_does_not_exist.html」を要求する場合と同じ方法で404エラーを処理します。コンテンツとステータスのないASP.NET応答コード2xxは影響を受けません。
ASP.NETがアプリケーションコードを使用して要求を完了できない場合、ASP.NETは内部コードを使用して要求を処理します。次の例を参照してください。
URLを解決できない場合、ASP.NETはそれ自体で応答を生成します。デフォルトでは、問題の詳細を含むHTML本文で404応答を作成します。代わりに、customErrorsを使用して302(リダイレクト)応答を作成できます。ただし、ASP.NETが404応答を返す原因となる有効なURLにアクセスしても、customErrorsで指定されたリダイレクトはトリガーされません。
ASP.NETがアプリケーションコードから例外をキャッチした場合も同じことが起こります。デフォルトでは、例外の原因となったソースコードに関する詳細を含むHTML本文で500応答を作成します。この場合も、customErrorsを使用して、代わりに302(リダイレクト)応答を生成できます。ただし、アプリケーションコードから500応答を作成しても、customErrorsで指定されたリダイレクトはトリガーされません。
defaultRedirectおよびerrorタグは、何を考慮して理解するのが非常に簡単です。私はちょうど言った。エラータグは、特定のステータスコードのリダイレクトを指定するために使用されます。対応するエラータグがない場合は、defaultRedirectが使用されます。リダイレクトURLは、コントローラーアクションを含め、サーバーが処理できるすべてのものを指すことができます。
ASP.NET MVCを使用すると、事態はさらに複雑になります。まず、2つの「Web.config」ファイルがあります。1つはルートにあり、もう1つはViewsフォルダーにあります。ビューのデフォルトの「Web.config」は、このスレッドに対して2つの重要なことを実行することに注意してください。
ASP.NET MVCの場合、HandleErrorAttributeを GlobalFilters に追加できます。これには、の値も考慮されます。ルート「Web.config」からのcustomErrorsタグのmode属性。具体的には、設定がオンの場合、コントローラー/アクションコードでキャッチされなかった例外のMVCレイヤーでのエラー処理が有効になります。それらをASP.NETに転送するのではなく、デフォルトでViews/Shared /Error.cshtmlをレンダリングします。これは、HandleErrorAttributeのViewプロパティを設定することで変更できます。
MVCレイヤーでのエラー処理は、リクエストURLに基づいて、コントローラー/アクションが解決された後に開始されます。たとえば、アクションのパラメータを満たさないリクエストは、MVCレイヤーで処理されます。ただし、POSTリクエストにPOSTを処理できる一致するコントローラー/アクションがない場合、エラーはASP.NETレイヤーで処理されます。
テストにはASP.NETMVC5を使用しました。エラー処理に関して、IISとIIS Expressの間に違いはないようです。
500以外のステータスコードでcustomErrorsが考慮されない理由を考えることができる唯一の理由は、それらがHttpStatusCodeResponseで作成されているためです。この場合、応答はアプリケーションコードによって作成され、ASP.NETではなくIISによって処理されます。この時点で、代替ページを構成することは無意味です。この動作を再現するサンプルコードを次に示します。
public ActionResult Unhandled404Error()
{
return new HttpStatusCodeResult(HttpStatusCode.NotFound);
}
このようなシナリオでは、OnResultExecuted
をオーバーライドして次のようなことを行う ActionFilterAttribute を実装することをお勧めします。
int statusCode = filterContext.HttpContext.Response.StatusCode;
if(statusCode >= 400)
{
filterContext.HttpContext.Response.Clear();
filterContext.HttpContext.Response.Redirect("/Home/Index");
}
実装されたActionFilterAttributeをGlobalFiltersに追加する必要があります。
この答えがあなたに役立つかどうかはわかりませんが、これは簡単な方法です...私はerror.htmlを/に配置し、Web構成のカスタムエラーに対してモードをオンにしました。これは完全に機能します...
<system.web>
<customErrors defaultRedirect="~/Error.html" mode="On" />
</system.web>
このerror.htmlは、頭と体のある基本的なhtmlページです。
コントローラErrorControllerを作成します。
public class ErrorController : Controller
{
//
// GET: /Error/
public ActionResult Index()
{
return View();
}
}
アクションのインデックスビューを作成します。
web.configで
<customErrors mode="On">
<error statusCode="404" redirect="Error/Index"/>
</customErrors>
コード/ロジックのエラーを処理しているとき
[HandleError]
public class HomeController : Controller
{
public ActionResult Index()
{
ViewBag.Message = "Modify this template to jump-start application.";
return View("Index2");
}
}
[HandleError]属性-共有フォルダー内のError.cshtmlページにリダイレクトされます。
私にとっては、デフォルトのError.cshtmlファイルを削除することで機能し、Web.configのカスタムErrordefaultRedirectページを取得しています。