نظرة عامة: يصف هذا القسم بشكل أساسي الاستثناءات والاستثناءات التي تمت محاكاتها والتي قد تحدث في استدعاءات الخدمة، ويحلل متى وما هي الاستثناءات التي يمكن اكتشافها، وكيفية تمرير استثناءات الخدمة إلى العميل بالطريقة الصحيحة.
في نهاية المقالة، يتم تقديم تسلسل الالتقاط لالتقاط الاستثناءات بشكل صحيح. يعد التقاط الاستثناء هذا مجرد مقدمة، وبعضها عبارة عن وظائف تطبيقية، لذا فإن التعليمات البرمجية والكتابة بسيطة نسبيًا، كما أنها تقدم بعض التقنيات لمعالجة الاستثناءات من جانب الخادم.
1. أولاً، نقوم بإنشاء خادم وعميل آلة حاسبة بسيطة، على النحو التالي:
انقر لتوسيع التعليمات البرمجية
// Server[ServiceContract]الواجهة العامة 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); [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); ) ) {return base.Channel.Div(x, y }});
حسنًا، أعترف أن الكود بسيط جدًا، لكني أحب الأشياء البسيطة.
2. الأشياء البسيطة جيدة، ودعونا نسميها أسهل بكثير؛
حاول { CalcClientcalcclient = new CalcClient(); على سبيل المثال) {رمي على سبيل المثال } التقاط (FaultExceptionex) {رمي على سبيل المثال؛ رمي على سبيل المثال؛
3. عندما نستدعي طريقة Div(int x, int y) للخدمة ونمرر القيمة 0 إلى اللوغاريتم y، فسيطرح الخادم استثناء DivideByZeroException، وهو أمر متوقع. في هذا الوقت،
تم اكتشاف هذا الاستثناء في قسم FaultException الخاص بالعميل.
4. لا توجد مشكلة، سنقوم يدويًا بطرح FaultException في رمز الخادم.
Catch (DivideByZeroException ex){FaultException Exception = new FaultException(ex.Message);}
في هذا الوقت، اكتشفت أن FaultException اكتشف هذا الاستثناء.
5. قم بإجراء اختبار آخر.
أضف هذا الرمز إلى الخدمة: System.Threading.Thread.Sleep(70000);
هذه المرة، اكتشف TimeOutException أخيرًا استثناء الخادم، لذا علينا أن نسأل متى سيتمكن FaultException<GreentingError> من اكتشاف الاستثناء؟ الجواب هو أنه عندما يقوم الخادم بطرح FaultException<GreentingError>، اقتبس مقطعًا على MSDN (الجزء الأخضر):
إذا تلقى المستمع خطأ SOAP غير متوقع أو محدد في عقد التشغيل، فسيتم طرح كائن FaultException ويمكن إرسال نوعين من أخطاء SOAP: المعلنة وغير المعلنة. خطأ SOAP المعلن هو الخطأ الذي تحتوي فيه العملية على سمة System.ServiceModel.FaultContractAttribute التي تحدد نوع خطأ SOAP مخصص. أخطاء SOAP غير المعلنة هي أخطاء غير محددة في عقد العملية. يشير "خطأ SOAP غير متوقع أو غير محدد" هنا إلى نوع خطأ مخصص غير متضمن مع FaultContractAttribute في عملية الخدمة.
6. إذن متى سيتم اكتشاف CommincationException؟
تقول MSDN: يتعامل التطبيق مع كائنات CommunicationException التي قد يتم طرحها أثناء الاتصال
حسنًا، من أجل رفع هذا الاستثناء، نقوم بما يلي. قم أولاً بإغلاق كائن القناة الحالي على الخادم.
OperationContext.Current.Channel.Close();
لسوء الحظ، لم يلتقط العميل CommunicationException، لكنه اكتشف TimeOutException! نظرًا لعدم حدوث أي استثناء بعد إغلاق قناة الخدمة، لم يتم إرجاع أي رسالة إلى العميل بعد الانتظار لفترة زمنية معينة، انتهت مهلة العميل وخرج.
لذلك نحدد TimeSpan أثناء إغلاق القناة. وهذا يسمح بإعادة المكالمة على الفور بالطبع، يمكن أيضًا إكمال إعادة المكالمة من خلال Channel.Abort.
OperationContext.Current.Channel.Close(new TimeSpan(5000));
عند استدعاء طريقة الإغلاق الخاصة بـ IContextChannel، حدد الوقت الذي يجب أن تكتمل فيه عملية الإرسال قبل انتهاء المهلة، بحيث يمكن إرجاع الرسالة على الفور خلال الوقت المحدد دون الحاجة إلى انتظار انتهاء مهلة استدعاء الخدمة، وإلا فسيرمي العميل بالتأكيد استثناء TimeOutException بدلاً من استثناء CommunicationException.
7. العلاجات
في الوقت نفسه، من أجل اتخاذ بعض التدابير العلاجية عند حدوث استثناء في الخدمة، قمنا بإنشاء فئة مجردة جديدة ServiceBase وجعلنا فئة تنفيذ خدمة Calc ترث منها، حتى نتمكن من التحكم في انتقالات الحالة المختلفة للخدمة الخدمة. فئة ServiceBase هي كما يلي:
فئة عامة مجردة جزئية ServiceBase { قناة IContextChannel الخاصة = null; protected ServiceBase() {channel = OperationContext.Current.Channel.Opening += new EventHandler(delegate(object sender, EventArgs e) {/* TO DO*/ }) ;channel.Opened += 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() }}
كما يتبين من الكود أعلاه، بعد إغلاق قناة الخدمة، نوقف الخدمة على الفور ونسمح للرسالة بالعودة على الفور، حتى لو تم إغلاق الخدمة أثناء العملية دون تحديد وقت انتهاء المهلة لا يزال بإمكانه العودة على الفور.
هذه المرة اكتشف العميل استثناء الاتصال أخيرًا، كما هو موضح في الشكل أدناه:
لماذا يحدث هذا؟
8. دعونا نلقي نظرة على التسلسل الهرمي لوراثة CommunicationException، والذي يمكننا أن نستمد منه الإلهام.
8.1 الأول هو التسلسل الهرمي لوراثة FaultException<TDetail>.
8.2، مرة أخرى التسلسل الهرمي لوراثة TimeOutException.
9. كما يتبين من الشكل أعلاه، يرث كل من TimeOutException وCommunicationException من فئة SystemException، بينما يرث FaultException من CommunicationException، وأخيرًا يرث FaultException<TDetail> من فئة FaultException.
10. أخيرًا، توصلنا إلى أن الترتيب الصحيح لالتقاط الاستثناءات على العميل يجب أن يكون كما يلي:
TimeOutException> FaultException<TDetail>> FaultException> CommunicationException> استثناء. يوصى بشدة أن يرمي المطورون ويلتقطوا استثناءات من النوع FaultException<TDetail>.
المؤلف: لاو مي المصدر: http://www.cnblogs.com/viter/
حقوق الطبع والنشر لهذه المقالة مملوكة للمؤلف ونرحب بإعادة الطباعة، ومع ذلك، يجب الاحتفاظ بهذا البيان دون موافقة المؤلف، ويجب توفير رابط للنص الأصلي في مكان واضح على صفحة المقالة. الحق في متابعة المسؤولية القانونية محفوظ.