ASP.NET 2.0 Web サービスでグローバル例外ハンドラ
ASP.NET Web サービス でも ASP.NET Web アプリケーションと同じように、Global.asax の Application_Error イベントで例外をハンドルできると思っていたらできなかったので回避策をメモ
何故ハンドル出来ないか?
ここによると、
Web サービスの HttpHandler は、Web サービスの実行中に発生した例外を処理し、その例外を Application_Error イベントを呼び出す前に SOAP 違反に変換します。
と、いうことらしい。
Soap 拡張機能
とりあえずクラスライブラリプロジェクトを作成し、例外を log4net でロギングするクラス LoggingExtension を作成してみた。
肝心なのは ProcessMessage メソッドで、SoapMessage クラスの Stage プロパティが AfterSerialize または BeforeSeialize の時、 Exception プロパティに SoapException が格納されている。その SoapException の InnerException プロパティに、実際に発生した例外が格納されているので、それを処理するようにした。
その他のメソッドは下記の実装でも特に問題ないようだ。
using System; using System.Web.Services.Protocols; using log4net; namespace Extensions { public class LoggingExtension : SoapExtension { private static readonly ILog logger = LogManager.GetLogger("default"); public override void ProcessMessage(SoapMessage message) { switch (message.Stage) { case SoapMessageStage.AfterSerialize: if (message.Exception != null) { logger.Error("",message.Exception.InnerException); } break; default: break; } } public override object GetInitializer(Type serviceType) { return null; } public override object GetInitializer( LogicalMethodInfo methodInfo, SoapExtensionAttribute attribute) { return null; } public override void Initialize(object initializer) { } } }
Web.config
Web サービスプロジェクトで上記のクラスライブラリを参照しただけでは不十分で、さらにWeb.config ファイルで以下の設定をする必要がある。
add タグは
<?xml version="1.0" encoding="utf-8" ?> <configuration> <appSettings/> <connectionStrings/> <system.web> <webServices> <soapExtensionTypes> <add type="Extensions.LoggingExtension, Extensions"/> </soapExtensionTypes> </webServices> </system.web> </configuration>
log4net でロギングされない場合
原因は良くわからないが、Web.config が単純なら上記の設定でロギングされる。なんだけど、Web.config が複雑になるとログが出力されないことがある。とりあえず Web サービスクラスで明示的に以下のコードを記述するときちんとロギングされるようになった。
log4net.Config.XmlConfigurator.Configure();