WebApi コントローラーが作成され、コンストラクターが HttpControllerActivators を介して呼び出されます。デフォルトのアクティベーターは System.Web.Http.Dispatcher.DefaultHttpControllerActivator です。
github のオプション 1 と 2 の非常に大まかな例https://github.com/markyjones/StackOverflow/tree/master/ControllerExceptionHandling/src
非常にうまく機能するオプション 1には、DI コンテナーの使用が含まれます (既に使用している可能性があります)。この例では Ninject を使用し、「インターセプター」を使用して、DefaultHttpControllerActivator の Create メソッドの呼び出しをインターセプトして試行/キャッチしました。少なくとも、次のようなことを実行できる AutoFac と Ninject を知っています。
インターセプターを作成する
あなたのマダガスカルとログ アイテムの有効期間はわかりませんが、インターセプターに注入される可能性は十分にあります
public class ControllerCreationInterceptor : Ninject.Extensions.Interception.IInterceptor
{
private ILog _log;
private IMadagascar _madagascar;
public ControllerCreationInterceptor(ILog log, IMadagascar madagascar)
{
_log = log;
_madagascar = madagascar;
}
しかし、ログとマダガスカルがある種の静的グローバルであるあなたの質問の例を維持してください
public class ControllerCreationInterceptor : Ninject.Extensions.Interception.IInterceptor
{
public void Intercept(Ninject.Extensions.Interception.IInvocation invocation)
{
try
{
invocation.Proceed();
}
catch(InvalidOperationException e)
{
if (e.InnerException is BubonicPlagueException)
{
Log.Error(e.InnerException, "CLOSE EVERYTHING!");
Madagascar.ShutdownAllPorts();
//DO SOMETHING WITH THE ORIGIONAL ERROR!
}
//DO SOMETHING WITH THE ORIGIONAL ERROR!
}
}
}
最後にインターセプターをグローバル asax または App_Start (NinjectWebCommon)に登録します。
kernel.Bind<System.Web.Http.Dispatcher.IHttpControllerActivator>()
.To<System.Web.Http.Dispatcher.DefaultHttpControllerActivator>().Intercept().With<ControllerCreationInterceptor>();
オプション 2は、IHttpControllerActivator インターフェイスを実装する独自の Controller Activator を実装し、Create メソッドで Controller の作成時のエラーを処理することです。デコレータ パターンを使用して、DefaultHttpControllerActivator をラップできます。
public class YourCustomControllerActivator : IHttpControllerActivator
{
private readonly IHttpControllerActivator _default = new DefaultHttpControllerActivator();
public YourCustomControllerActivator()
{
}
public System.Web.Http.Controllers.IHttpController Create(System.Net.Http.HttpRequestMessage request, System.Web.Http.Controllers.HttpControllerDescriptor controllerDescriptor, Type controllerType)
{
try
{
return _default.Create(request, controllerDescriptor, controllerType);
}
catch (InvalidOperationException e)
{
if (e.InnerException is BubonicPlagueException)
{
Log.Error(e.InnerException, "CLOSE EVERYTHING!");
Madagascar.ShutdownAllPorts();
//DO SOMETHING WITH THE ORIGIONAL ERROR!
}
//DO SOMETHING WITH THE ORIGIONAL ERROR!
return null;
}
}
}
独自のカスタム アクティベーターを作成したら、グローバル asax でデフォルト アクティベーターを切り替えることができます。
GlobalConfiguration.Configuration.Services.Replace(typeof(IHttpControllerActivator), new YourCustomControllerActivator());
オプション3もちろん、コンストラクターでの初期化が実際のコントローラーメソッド、プロパティなどにアクセスする必要がない場合...つまり、コンストラクターから削除できると仮定すると...初期化を移動するだけの方がはるかに簡単ですフィルタなど
public class MadagascarFilter : AbstractActionFilter
{
public override void OnActionExecuting(System.Web.Http.Controllers.HttpActionContext actionContext)
{
try{
DoSomeInitialization(); // this can throw an exception
}
catch(BubonicPlagueException e){
Log.Error(e, "CLOSE EVERYTHING!");
Madagascar.ShutdownAllPorts();
//DO SOMETHING WITH THE ERROR
}
base.OnActionExecuting(actionContext);
}
public override void OnActionExecuted(System.Web.Http.Filters.HttpActionExecutedContext actionExecutedContext)
{
base.OnActionExecuted(actionExecutedContext);
}
public override bool AllowMultiple
{
get { return false; }
}
}