Overview: This section mainly describes exceptions and simulated exceptions that may occur in service calls, and analyzes when and what exceptions can be caught, and how to pass service exceptions to the client in the correct way.
At the end of the article, the catching sequence for correctly catching exceptions is given. This exception capture is only an introduction, and some of it is application functions, so the code and writing are relatively simple. It also introduces some techniques for exception handling on the server side.
1. First, we create a simple calculator server and client, as follows:
Click to expand code
//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; }return result; }}//Client [ServiceContract] public interface 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); }}
Okay, I admit that the code is quite simple, but I like simple things.
2. Simple things are good, and calling them is much simpler; let’s call them.
try { CalcClientcalcclient = new CalcClient(); string result =calcclient.Div(10, 0); Console.WriteLine(result); Console.ReadKey(); } catch (TimeoutExceptionex) {throw ex; } catch (FaultException<GreentingError> ex) {throw ex; } catch (FaultExceptionex) {throw ex; catch (System.ServiceModel.CommunicationException ex) {throw ex; } catch (Exceptionex) {throw ex; }
3. When we call the Div(int x, int y) method of the service and pass the value 0 to the logarithm y, the server will throw a DivideByZeroException exception, which is expected. At this time,
This exception is caught in the FaultException section of the client.
4. No problem, we will manually throw FaultException in the server code.
catch (DivideByZeroException ex){FaultException exception = new FaultException(ex.Message); throw exception;}
At this time, I found that FaultException caught this exception. Why?
5. Do another test.
Add this code to the service: System.Threading.Thread.Sleep(70000); to cause the service to time out.
This time, TimeOutException finally caught the server exception, so we have to ask, when will FaultException<GreentingError> catch the exception? The answer is that when the server throws FaultException<GreentingError>, quote a passage on MSDN (green part):
If the listener receives a SOAP error that is not expected or specified in the operation contract, a FaultException object will be thrown. Two types of SOAP errors can be sent: declared and undeclared. A declared SOAP error is one in which an operation has the System.ServiceModel.FaultContractAttribute attribute that specifies a custom SOAP error type. Undeclared SOAP errors are errors that are not specified in the operation's contract. The "unexpected or unspecified SOAP error" here refers to a custom error type that is not wrapped with FaultContractAttribute in the service operation.
6. So when will CommincationException be caught?
MSDN says: Application handles CommunicationException objects that may be thrown during communication
Well, in order to raise this exception, we do the following. First close the current channel object on the server.
OperationContext.Current.Channel.Close();
Unfortunately, the client did not catch CommunicationException, but caught TimeOutException! Because no exception occurred after the service channel was closed, no message was returned to the client. After waiting for a certain period of time, the client timed out and exited.
So we specify a TimeSpan while closing the channel. This allows the call to return immediately. Of course, the call return can also be completed through Channel.Abort.
OperationContext.Current.Channel.Close(new TimeSpan(5000));
When calling the Close method of IContextChannel, specify the time that the sending operation must be completed before timeout, so that the message can be returned immediately within the specified time without having to wait for the service call to timeout, otherwise the client will definitely throw a TimeOutException exception. Instead of CommunicationException exception.
7. Remedies
At the same time, in order to take some remedial measures when an exception occurs in the service, we created a new abstract class ServiceBase and made the Calc service implementation class inherit from it, so that we can gain control over the various state transitions of the service. The ServiceBase class is as follows:
public abstract partial class ServiceBase { private IContextChannel channel = null; protected ServiceBase() { channel = OperationContext.Current.Channel; channel.Opening += 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(); }}
As can be seen from the above code, after the service channel is closed, we immediately stop the service and let the message return immediately. At this time, even if the service is closed during the operation without specifying the timeout completion time, the call can still return immediately.
This time the client finally caught the CommunicationException, as shown in the figure below:
Why is this happening?
8. Let us take a look at the inheritance hierarchy of CommunicationException, from which we can get inspiration.
8.1. The first is the inheritance hierarchy of FaultException<TDetail>.
8.2, again the inheritance hierarchy of TimeOutException.
9. As can be seen from the above figure, TimeOutException and CommunicationException both inherit from the SystemException class, while FaultException inherits from CommunicationException, and finally FaultException<TDetail> inherits from the FaultException class.
10. Finally, we concluded that the correct order of catching exceptions on the client should be:
TimeOutException> FaultException<TDetail> > FaultException > CommunicationException > Exception. It is strongly recommended that developers throw and catch exceptions of type FaultException<TDetail>.
Author: Lao Mi Source: http://www.cnblogs.com/viter/
The copyright of this article belongs to the author and Blog Park. Reprinting is welcome. However, this statement must be retained without the author's consent, and a link to the original text must be provided in an obvious position on the article page. Otherwise, the right to pursue legal liability is reserved.