.NET 3.5.
私が実装したパターンは、web.config で .NET のカスタム リダイレクト ソリューションをバイパスします。これは、ヘッダーに正しい HTTP ステータス コードを含むすべてのシナリオを処理する独自のパターンを作成したためです。
まず、web.config の customErrors セクションは次のようになります。
<customErrors mode="RemoteOnly" defaultRedirect="~/error.htm" />
この設定により、CustomErrors モードが確実に on に設定されます。この設定は後で必要になります。また、error.htm の defaultRedirect に all-else-fails オプションを提供します。これは、特定のエラーのハンドラーがない場合や、データベース接続が壊れているような場合に役立ちます。
次に、グローバル asax エラー イベントを次に示します。
protected void Application_Error(object sender, EventArgs e)
{
HandleError();
}
private void HandleError()
{
var exception = Server.GetLastError();
if (exception == null) return;
var baseException = exception.GetBaseException();
bool errorHandled = _applicationErrorHandler.HandleError(baseException);
if (!errorHandled) return;
var lastError = Server.GetLastError();
if (null != lastError && HttpContext.Current.IsCustomErrorEnabled)
{
Elmah.ErrorSignal.FromCurrentContext().Raise(lastError.GetBaseException());
Server.ClearError();
}
}
このコードは、エラーを処理する責任を別のクラスに渡しています。エラーが処理されず、CustomErrors がオンになっている場合、それは、本番環境にあり、エラーが処理されていないというケースがあることを意味します。ユーザーに見えないようにここでクリアしますが、Elmah にログを記録して、何が起こっているかを把握します。
applicationErrorHandler クラスは次のようになります。
public bool HandleError(Exception exception)
{
if (exception == null) return false;
var baseException = exception.GetBaseException();
Elmah.ErrorSignal.FromCurrentContext().Raise(baseException);
if (!HttpContext.Current.IsCustomErrorEnabled) return false;
try
{
var behavior = _responseBehaviorFactory.GetBehavior(exception);
if (behavior != null)
{
behavior.ExecuteRedirect();
return true;
}
}
catch (Exception ex)
{
Elmah.ErrorSignal.FromCurrentContext().Raise(ex);
}
return false;
}
このクラスは基本的にコマンド パターンを使用して、発行されたエラーの種類に適したエラー ハンドラーを見つけます。ほとんどすべてのエラーが上位レベルの例外にラップされるため、このレベルで Exception.GetBaseException() を使用することが重要です。たとえば、任意の aspx ページから "throw new System.Exception()" を実行すると、System.Exception ではなく、このレベルで HttpUnhandledException が受信されます。
「ファクトリー」コードは単純で、次のようになります。
public ResponseBehaviorFactory()
{
_behaviors = new Dictionary<Type, Func<IResponseBehavior>>
{
{typeof(StoreException), () => new Found302StoreResponseBehavior()},
{typeof(HttpUnhandledException), () => new HttpExceptionResponseBehavior()},
{typeof(HttpException), () => new HttpExceptionResponseBehavior()},
{typeof(Exception), () => new Found302DefaultResponseBehavior()}
};
}
public IResponseBehavior GetBehavior(Exception exception)
{
if (exception == null) throw new ArgumentNullException("exception");
Func<IResponseBehavior> behavior;
bool tryGetValue = _behaviors.TryGetValue(exception.GetType(), out behavior);
//default value here:
if (!tryGetValue)
_behaviors.TryGetValue(typeof(Exception), out behavior);
if (behavior == null)
Elmah.ErrorSignal.FromCurrentContext().Raise(
new Exception(
"Danger! No Behavior defined for this Exception, therefore the user might have received a yellow screen of death!",
exception));
return behavior();
}
最後に、拡張可能なエラー処理スキームのセットアップを取得しました。定義されている「動作」のそれぞれに、エラーのタイプのカスタム実装があります。たとえば、HTTP 例外はステータス コードを検査され、適切に処理されます。404 ステータス コードには、Request.Redirect の代わりに Server.Transfer が必要であり、ヘッダーに適切なステータス コードが書き込まれています。
お役に立てれば。