概要: このセクションでは主に、サービス呼び出しで発生する可能性のある例外とシミュレートされた例外について説明し、いつ、どのような例外をキャッチできるか、およびサービス例外をクライアントに正しい方法で渡す方法を分析します。
この記事の最後には、例外を正しくキャッチするためのキャッチ シーケンスが記載されています。この例外キャプチャは単なる導入であり、その一部はアプリケーション関数であるため、コードと記述は比較的単純です。また、サーバー側での例外処理のテクニックもいくつか紹介されています。
1. まず、次のように単純な計算サーバーとクライアントを作成します。
クリックしてコードを展開します
//Server[ServiceContract]public Interface ICalc{[OperationContract][FaultContract(typeof(GreentingError))]string Div(int x, int y);}public class Calc : ServiceBase, ICalc {public string Div(int x, int y) ) ) {string result = string.Empty; try {result = string.Format("result: {0}", x / y); } catch (DivideByZeroException ex) {throw ex }}//クライアント[ServiceContract] パブリックインターフェイス ICalc { [OperationContract] [FaultContract(typeof(GreentingError))] string Div(int x, int y) } public class CalcClient : ClientBase<ICalc>, ICalc{ public string Div(int x, int y) ) ) {戻りbase.Channel.Div(x, y) }}
コードが非常に単純であることは認めますが、私はシンプルなものが好きです。
2. シンプルなものは良いもので、呼び出しはもっと簡単です。
try { CalcClientcalcclient = new CalcClient(); string result =calcclient.Div(10, 0); Console.ReadKey(); } catch (TimeoutExceptionex) {throw ex; ex) {スロー ex; } キャッチ (FaultExceptionex) {スロー ex;
3. サービスの Div(int x, int y) メソッドを呼び出し、値 0 を対数 y に渡すと、サーバーは予期されている DivideByZeroException 例外をスローします。現時点では、
この例外は、クライアントの FaultException セクションでキャッチされます。
4. 問題ありません。サーバー コードで FaultException を手動でスローします。
catch (DivideByZeroException ex){FaultException 例外 = new FaultException(ex.Message);}
このとき、FaultException がこの例外をキャッチしたことがわかりました。なぜでしょうか。
5. 別のテストを実行します。
次のコードをサービスに追加します: System.Threading.Thread.Sleep(70000); サービスをタイムアウトさせます。
今回は、TimeOutException がついにサーバー例外をキャッチしたため、FaultException<GreentingError> が例外をいつキャッチするのかを尋ねる必要があります。答えは、サーバーが FaultException<GreentingError> をスローしたときに、MSDN の一節 (緑色の部分) を引用することです。
リスナーが、予期されていない、または操作コントラクトで指定されていない SOAP エラーを受信した場合、FaultException オブジェクトがスローされる可能性があります。宣言された SOAP エラーと宣言されていない SOAP エラーの 2 種類です。 宣言された SOAP エラーとは、操作にカスタム SOAP エラー タイプを指定する System.ServiceModel.FaultContractAttribute 属性があるエラーです。 未宣言の SOAP エラーは、操作のコントラクトに指定されていないエラーです。ここでの「予期しない、または指定されていない SOAP エラー」とは、サービス操作で FaultContractAttribute でラップされていないカスタム エラー タイプを指します。
6. では、CommincationException はいつキャッチされるのでしょうか?
MSDN によると: アプリケーションは通信中にスローされる可能性のある CommunicationException オブジェクトを処理します
さて、この例外を発生させるために、次のことを行います。まず、サーバー上の現在のチャネル オブジェクトを閉じます。
OperationContext.Current.Channel.Close();
残念ながら、クライアントは CommunicationException をキャッチしませんでしたが、TimeOutException をキャッチしました。サービス チャネルが閉じられた後、例外が発生しなかったため、クライアントにメッセージが返されず、一定時間待機した後、クライアントはタイムアウトして終了しました。
したがって、チャネルを閉じるときに TimeSpan を指定します。これにより、通話はすぐに戻ることができます。もちろん、Channel.Abort を通じて通話を返すこともできます。
OperationContext.Current.Channel.Close(new TimeSpan(5000));
IContextChannel の Close メソッドを呼び出すときに、タイムアウトになる前に送信操作が完了する必要がある時間を指定します。これにより、サービス呼び出しがタイムアウトするのを待たずに、指定された時間内にメッセージをすぐに返すことができます。そうしないと、クライアントは確実にスローします。 CommunicationException 例外の代わりに、TimeOutException 例外。
7. 救済策
同時に、サービスで例外が発生した場合に何らかの救済策を講じるために、新しい抽象クラス ServiceBase を作成し、それを Calc サービス実装クラスに継承させ、サービスのさまざまな状態遷移を制御できるようにしました。サービス。 ServiceBase クラスは次のとおりです。
パブリック抽象部分クラス ServiceBase { private IContextChannel チャネル = null; protected ServiceBase() { チャネル = OperationContext.Current.Channel; チャネル.オープニング += new EventHandler(delegate(object sender, EventArgs e) {/* TO DO*/ }) ; channel.Opened += new EventHandler(delegate(object sender, EventArgs e) {/* TO DO*/ }); channel.Closing += new EventHandler(delegate(object sender, EventArgs e) {/* TO DO*/ }); channel.Closed += new EventHandler(delegate(object sender, EventArgs e) { Abort(); }); channel.Faulted += new EventHandler(delegate(object sender, EventArgs e) { Abort(); }) ; } void Open() {/* TO DO*/ } void Close() { /* TO DO*/} void Abort() { channel.Abort();
上記のコードからわかるように、サービス チャネルが閉じられた後、すぐにサービスを停止し、タイムアウト完了時間を指定せずに操作中にサービスが閉じられた場合でも、すぐにメッセージを返します。まだすぐに戻ることができます。
次の図に示すように、今回はクライアントが最終的に CommunicationException をキャッチしました。
なぜこのようなことが起こっているのでしょうか?
8. CommunicationException の継承階層を見てみましょう。そこからインスピレーションが得られます。
8.1. 1 つ目は、FaultException<TDetail> の継承階層です。
8.2、再び TimeOutException の継承階層。
9. 上の図からわかるように、TimeOutException と CommunicationException は両方とも SystemException クラスから継承され、FaultException は CommunicationException から継承され、最後に FaultException<TDetail> は FaultException クラスから継承されます。
10. 最後に、クライアントで例外をキャッチする正しい順序は次のとおりであると結論付けました。
TimeOutException> FaultException<TDetail> > FaultException > CommunicationException > 例外。開発者は、FaultException<TDetail> 型の例外をスローおよびキャッチすることを強くお勧めします。
著者: Lao Mi 出典: http://www.cnblogs.com/viter/
この記事の著作権は著者に帰属しており、転載は歓迎します。ただし、この記述は著者の承諾なしに保持し、記事ページのわかりやすい位置に原文へのリンクを掲載する必要があります。法的責任を追及する権利は留保されます。