例外処理はプログラミングにおいて非常に重要であり、ユーザーフレンドリーなヒントを与えることができ、プログラムのセキュリティのためにも重要です。ASP.NET Coreでは、デフォルトで多くのソリューションが提供されています。
1. コントローラを継承し、OnActionExecutedをオーバーライド
vs new controllerを使用すると、デフォルトではControllerクラスを継承し、OnActionExecutedをオーバーライドし、例外処理を追加します。通常、新しいBaseControllerを作成し、すべてのControllerがBaseControllerを継承するようにします。コードは以下の通り
public class BaseController : Controller
{
public override void OnActionExecuted(ActionExecutedContext context)
{
var exception = context.Exception;
if (exception != null)
{
context.ExceptionHandled = true;
context.Result = new ContentResult
{
Content = $"BaseController错误 : { exception.Message }"
};
}
base.OnActionExecuted(context);
}
}
この処理方法の利点はもちろん簡単ですが、欠点は明らかです。CShtmlページが間違って投げられた場合、完全にキャッチすることはできません。もちろん、プロジェクト自体がWeb APIプロジェクトであり、ビューがない場合は、これは問題ありません。
2. ActionFilterAttributeの操作
ActionFilterAttributeは、IActionFilterおよびIResultFilterを実装した機能であるため、アクションでのエラー、ビューでのエラーのいずれも、理論的にはキャプチャできます。新しいExceptionActionFilterAttributeを作成し、OnActionExecutedとOnResultExecutedを書き換え、例外処理を追加します。
public class ExceptionActionFilterAttribute:ActionFilterAttribute
{
public override void OnActionExecuted(ActionExecutedContext context)
{
var exception = context.Exception;
if (exception != null)
{
context.ExceptionHandled = true;
context.Result = new ContentResult
{
Content = $"错误 : { exception.Message }"
};
}
base.OnActionExecuted(context);
}
public override void OnResultExecuted(ResultExecutedContext context)
{
var exception = context.Exception;
if (exception != null)
{
context.ExceptionHandled = true;
context.HttpContext.Response.WriteAsync($"错误 : {exception.Message}");
}
base.OnResultExecuted(context);
}
}
利用方法は2種類あり、
- controllerに[TypeFilter typeof ExceptionActionFilter]ラベルを付けます。
- Startupではフィルターでグローバルに注入します。
services.AddControllersWithViews(options =>
{
options.Filters.Add<ExceptionActionFilterAttribute>();
})
3. IExceptionFilterを使用する
ASP.NET Coreには5種類のフィルタがあります。IExceptionFilterはそのうちの1つです。名前が示すとおり、例外を処理するためのものです。IExceptionFilterはASP.NET CoreのExceptionFilterAttributeに実装されているため、ExceptionFilterAttributeを継承してメソッドをオーバーライドするだけです。CustomExceptionFilterAttributeもExceptionFilterAttributeを継承し、OnExceptionをオーバーライドし、例外処理を追加します。
public class CustomExceptionFilterAttribute : ExceptionFilterAttribute
{
public override void OnException(ExceptionContext context)
{
context.ExceptionHandled = true;
context.HttpContext.Response.WriteAsync($"CustomExceptionFilterAttribute错误:{context.Exception.Message}");
base.OnException(context);
}
}
ExceptionFilterAttributeは非同期メソッドOnExceptionAsyncも提供しています。どちらも1つをオーバーライドするだけで済み、両方をオーバーライドすると両方のメソッドが一度実行されます。
利用方法は2種類あり、
- コントローラに[CustomExceptionFilter]ラベルを付けます。
- Startupではフィルターでグローバルに注入します。
services.AddControllersWithViews(options =>
{
options.Filters.Add<CustomExceptionFilterAttribute>();
})
4. ExceptionHandlerの使い方
スタートアップでは、VS新規プロジェクトがデフォルトで追加されます。
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Home/Error");
}
上のコードは、開発環境がapp.UseDeveloperExceptionPage;を使用することを意味します。ホーム/エラーページに移動します。
UseDeveloperExceptionPageには、スタックトレース、クエリ、クッキー、ヘッダーなどのエラーメッセージが表示されます。net core 3.1以降は、リクエストヘッダにaccept text/htmlを追加するとhtmlページが返され、追加しないとエラーのみが返されるように変更されました。
注app.UseDeveloperExceptionPage;は先頭に配置してください。
if (!env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler(builder =>
{
builder.Run(async context =>
{
var exceptionHandlerPathFeature = context.Features.Get<IExceptionHandlerPathFeature>();
await context.Response.WriteAsync($"error:{exceptionHandlerPathFeature.Error.Message}");
});
});
}
5. カスタムMiddleare処理
ミドルウェアで処理されます。
public class ErrorHandlingMiddleware
{
private readonly RequestDelegate next;
public ErrorHandlingMiddleware(RequestDelegate next)
{
this.next = next;
}
public async Task Invoke(HttpContext context)
{
try
{
await next(context);
}
catch (System.Exception ex)
{
//处理异常
}
}
}