C#で書くExtensionで発生した例外は、OutSystemsのLow-Code部分でどう処理されるのかを確認してみます。
Extensionで色々なパターンで例外を発生させてみて、Action Flowでどの様にHandleされるか。
確認環境
Personal Environment(Version 11.12.0 (Build 30002))
Service Studio (Version 11.11.6)
Integration Studio (Version 11.11.5)
サンプルモジュール
ForgeコンポーネントのV1.0.10。
MainFlow > Exception Screen
結論
Extensionで発生した例外はAllExceptionsでハンドルする。
ハンドルした例外のExceptionMessageプロパティには、C#例外オブジェクトのmessageが設定される。
Exceptionが入れ子になっている(InnerExceptionが設定されている)場合でも一番上位の例外のmessageしか取れない。
Service CenterのErrorログでStack欄を見れば、Extension内の例外の発生順序は確認できる。
Extension Actionで直接発生した例外
以下のように、Extension Actionの先頭でいきなり例外をthrowさせた場合。
MyExceptionはテンプレートそのままのシンプルな例外クラス。
public void MssExceptionTest1() {
if (1 == 1)
throw new MyException("Actionメソッドから直接例外をthrowする");
}
Action Flowでは、各種の例外に対してHandle Exceptionを置いて、デバッガでどのパスに来るかを確認しました。
以下の通り、AllExceptionsでHandleされ、Extension内で例外オブジェクトに渡したメッセージが、ExceptionMessageプロパティに届いてます。UserExceptionとかではハンドルできないんですね。Extensionで発生した例外について、Action Flowで利用できるのは、せいぜい「例外が発生した事実」と「例外メッセージ」くらい。
Error Log (Service Center)に出力された、Source=「Extension metho」のログのStack。
Actionメソッドから直接例外をthrowする
at OutSystems.NssExceptionExtension.CssExceptionExtension.MssExceptionTest1()
at ssAssociateReactive.RssExtensionExceptionExtension.MssExceptionTest1(HeContext heContext)
別のクラスで発生した例外
Extension Actionから別のclassのメソッドを呼び出し、そこで例外を発生させた場合。
Extension Actionでは例外処理しない場合
例外を発生させるClass1.method1()を呼び、try-catchによる処理はしない場合。
public void MssExceptionTest2() {
var obj = new Class1();
obj.method1(); // throw new MyException("他のclassで例外を発生させる");
}
この場合もAllExceptions。呼び出したclassで設定した例外メッセージが、ExceptionMessageプロパティに。
Stack。
他のclassで例外を発生させる
at OutSystems.NssExceptionExtension.Class1.method1()
at ssAssociateReactive.RssExtensionExceptionExtension.MssExceptionTest2(HeContext heContext)
Extension Actionで例外をリスローした場合
try-catchで例外を発生させる処理を囲み、catchした例外には手を触れずにそのままリスローする場合。
public void MssExceptionTest3() {
try
{
var obj = new Class1();
obj.method1(); // throw new MyException("他のclassで例外を発生させる");
}
catch (Exception)
{
throw;
}
}
ExceptionMessageは例外をcatchしなかった場合と同じ。
Stackを確認すると、2行目にthrow;を行っているメソッドが追加されています。
他のclassで例外を発生させる
at OutSystems.NssExceptionExtension.Class1.method1()
at OutSystems.NssExceptionExtension.CssExceptionExtension.MssExceptionTest3()
at ssAssociateReactive.RssExtensionExceptionExtension.MssExceptionTest3(HeContext heContext)
Extension Actionでcatchした例外を詰め直す
C#では、try-catchのcatch内で同じ例外をthrowする場合、「throw;」として、「throw ex;」みたいな書き方をしないようにすすめられています。そのおすすめにあえて反した場合どうなるか。catchした例外を別の例外クラスのオブジェクトにくるんで(InnerExceptionとして渡して)throwしています。
public void MssExceptionTest4() {
try
{
var obj = new Class1();
obj.method1();
}
catch (Exception e)
{
throw new My2Exception("catchした例外を他の例外にラップしてthrowする", e);
}
}
ExceptionMessageには、InnerException(上記コードの「e」オブジェクト)の例外メッセージではなく、throwした例外オブジェクト自体の例外メッセージが設定されていますね。InnerExceptionはロジックから触ることができないようです(リフレクションとか使えば別でしょうが)。
Stackは以下のように2つに別れました。
[1] catchした例外を他の例外にラップしてthrowする
at OutSystems.NssExceptionExtension.CssExceptionExtension.MssExceptionTest4()
at ssAssociateReactive.RssExtensionExceptionExtension.MssExceptionTest4(HeContext heContext)
[2] 他のclassで例外を発生させる
at OutSystems.NssExceptionExtension.Class1.method1()
at OutSystems.NssExceptionExtension.CssExceptionExtension.MssExceptionTest4()
例外的ケース:DatabaseException
以下のように、C#でDatabaseExceptionをthrowしたら、Action Flowでも同名のDataBaseExceptionでハンドルできました。
これはおそらく、OutSystemsのDatabaseExceptionを.NETにコンパイルするときに、.NETのDatabaseExceptionクラスに解決しているということと思われます。つまり、このようにたまたま対応する例外クラスを見つけられる場合は、その例外クラスをthrowすることでAction Flowの分岐にも使えるかもしれない。ただ、ドキュメントにも特に記載が無いようだし、これをあてにした処理を書くのはおすすめできませんが。
public void MssExceptionTest5() {
if (1 == 1)
throw new DataBaseException("DatabaseExceptionを直接throwしてみる");
}