ภาพรวม: ส่วนนี้ส่วนใหญ่จะอธิบายข้อยกเว้นและข้อยกเว้นจำลองที่อาจเกิดขึ้นในการเรียกบริการ และวิเคราะห์เมื่อใดและข้อยกเว้นใดที่สามารถตรวจพบได้ และวิธีการส่งข้อยกเว้นบริการไปยังไคลเอนต์ด้วยวิธีที่ถูกต้อง
ในตอนท้ายของบทความ จะมีการกำหนดลำดับการจับสำหรับการจับข้อยกเว้นอย่างถูกต้อง การจับข้อยกเว้นนี้เป็นเพียงการแนะนำ และบางส่วนเป็นฟังก์ชันของแอปพลิเคชัน ดังนั้นโค้ดและการเขียนจึงค่อนข้างง่าย นอกจากนี้ยังแนะนำเทคนิคบางอย่างสำหรับการจัดการข้อยกเว้นในฝั่งเซิร์ฟเวอร์
1. ขั้นแรก เราสร้างเซิร์ฟเวอร์และไคลเอนต์เครื่องคิดเลขอย่างง่าย ดังนี้:
คลิกเพื่อขยายโค้ด
//เซิร์ฟเวอร์[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); } catch (DivideByZeroException เช่น) {throw ex; } ส่งคืนผลลัพธ์; [ServiceContract] อินเทอร์เฟซสาธารณะ ICalc { [OperationContract] [FaultContract(typeof(GreentingError))] string Div(int x, int y); } คลาสสาธารณะ CalcClient : ClientBase<ICalc>, ICalc{ สตริงสาธารณะ Div(int x, int y) ) ) { กลับฐาน Channel.Div(x, y); }}
โอเค ฉันยอมรับว่าโค้ดนั้นค่อนข้างง่าย แต่ฉันชอบสิ่งที่เรียบง่าย
2. สิ่งที่เรียบง่ายนั้นดี และการเรียกมันนั้นง่ายกว่ามาก มาเรียกมันกันดีกว่า
ลอง { CalcClientcalcclient = new CalcClient(); string result =calcclient.Div(10, 0); Console.WriteLine(result); Console.ReadKey(); } catch (TimeoutExceptionex) {throw ex; เช่น) {throw ex; } catch (FaultEx) {throw ex;
3. เมื่อเราเรียกใช้เมธอด Div(int x, int y) ของบริการและส่งค่า 0 ไปยังลอการิทึม y เซิร์ฟเวอร์จะส่งข้อยกเว้น DivideByZeroException ซึ่งคาดว่าจะเกิดขึ้น ในเวลานี้
ข้อยกเว้นนี้ติดอยู่ในส่วน FaultException ของไคลเอ็นต์
4. ไม่มีปัญหา เราจะโยน FaultException ลงในรหัสเซิร์ฟเวอร์ด้วยตนเอง
จับ (DivideByZeroException เช่น) {ข้อยกเว้น FaultException = ใหม่ FaultException (เช่นข้อความ); }
ในเวลานี้ ฉันพบว่า FaultException พบข้อยกเว้นนี้ เพราะเหตุใด
5. ทำการทดสอบอีกครั้ง
เพิ่มรหัสนี้ในบริการ: System.Threading.Thread.Sleep(70000); เพื่อทำให้บริการหมดเวลา
คราวนี้ TimeOutException ตรวจพบข้อยกเว้นของเซิร์ฟเวอร์ในที่สุด ดังนั้นเราต้องถามว่าเมื่อใดที่ FaultException<GreentingError> จะตรวจจับข้อยกเว้น คำตอบคือเมื่อเซิร์ฟเวอร์ส่ง FaultException<GreentingError> ให้อ้างอิงข้อความบน MSDN (ส่วนสีเขียว):
หากผู้ฟังได้รับข้อผิดพลาด SOAP ที่ไม่ได้คาดหวังหรือระบุไว้ในสัญญาการดำเนินการ ข้อผิดพลาด 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 (ระยะเวลาใหม่ (5000));
เมื่อเรียกใช้เมธอด Close ของ IContextChannel ให้ระบุเวลาที่การดำเนินการส่งต้องเสร็จสิ้นก่อนหมดเวลาเพื่อให้สามารถส่งข้อความกลับได้ทันทีภายในเวลาที่กำหนดโดยไม่ต้องรอให้เรียกใช้บริการจนหมดเวลา ไม่เช่นนั้น ลูกค้าจะโยนแน่นอน ข้อยกเว้น TimeOutException แทนที่จะเป็นข้อยกเว้น CommunicationException
7. การเยียวยา
ในเวลาเดียวกัน เพื่อใช้มาตรการแก้ไขเมื่อมีข้อยกเว้นเกิดขึ้นในบริการ เราได้สร้างคลาสนามธรรมใหม่ ServiceBase และทำให้คลาสการใช้งานบริการ Calc สืบทอดมาจากคลาสนั้น เพื่อให้เราสามารถควบคุมการเปลี่ยนสถานะต่างๆ ของ บริการ คลาส ServiceBase เป็นดังนี้:
ServiceBase คลาสนามธรรมสาธารณะ { ช่อง IContextChannel ส่วนตัว = null; protected ServiceBase () { channel = OperationContext.Current.Channel; channel.Opening += new EventHandler (ผู้รับมอบสิทธิ์ (ผู้ส่งวัตถุ EventArgs e) {/* TO DO*/ }) ; channel.Opened += new EventHandler(ผู้รับมอบสิทธิ์(ผู้ส่งวัตถุ EventArgs e) {/* TO DO*/ }); channel.Closed += new EventHandler(ผู้รับมอบสิทธิ์ (ผู้ส่งวัตถุ EventArgs e) { ยกเลิก (); }) ; } ถือเป็นโมฆะ Open() {/* TO DO*/ } void Close() { /* TO DO*/} ยกเลิก () { channel.Abort( }}
ดังที่เห็นได้จากโค้ดข้างต้น หลังจากปิดช่องทางบริการแล้ว เราจะหยุดบริการทันทีและปล่อยให้ข้อความกลับมาทันที ในเวลานี้ แม้ว่าบริการจะปิดระหว่างการดำเนินการโดยไม่ระบุเวลาสิ้นสุดการหมดเวลาก็ตาม การโทรก็ตาม ยังสามารถกลับมาได้ทันที
คราวนี้ไคลเอ็นต์ตรวจพบ CommunicationException ในที่สุด ดังแสดงในรูปด้านล่าง:
ทำไมสิ่งนี้ถึงเกิดขึ้น?
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/
ลิขสิทธิ์ของบทความนี้เป็นของผู้เขียนและ Blog Park อย่างไรก็ตาม จะต้องคงข้อความนี้ไว้โดยไม่ได้รับความยินยอมจากผู้เขียน และต้องระบุลิงก์ไปยังข้อความต้นฉบับในตำแหน่งที่ชัดเจนในหน้าบทความ สงวนสิทธิ์ในการดำเนินการรับผิดทางกฎหมาย