Error handling wcf

This article describes the WCF error-handling paradigm, and provides a mechanism for automatic mapping of exceptions to WCF faults.
  • Download source — 9.32 KB

Introduction

WCF seems like an easy technology to master. It serves as the ultimate example of framework design — it is simple for simple tasks, and not too complicated for complex ones; it is extensible and replaceable; its API is well-designed and convenient. One of the greatest challenges I encountered with WCF has to do with overcoming a very natural tendency .NET developers have: The Fallacy of the .NET-Only World.

WCF is designed for service orientation, and it is easy indeed to write explicitly demarcated services using WCF. Such services will grow to be first-class citizens in today’s interoperable world, revolving around dozens of constantly changing standards. However, it is also immensely easy to write coupled .NET-to-.NET solutions, even if you didn’t intend to.

There are numerous areas in which this coupling can manifest itself, threaded through contract design, service boundaries, error handling — nearly every aspect of a proper service. For example, it might seem very natural to use a class hierarchy as the foundation of a data contract for a WCF service. However, the very concept of inheritance is alien to the service world: it is a concept from object-oriented programming — a .NET concept, not a service concept. Another example is error handling — what could be more natural than throwing an exception to indicate failure? But, exceptions are again a .NET concept — what value does a service stack trace provide to the service consumer? How can exception data be propagated and consumed? What does an exception hierarchy mean, bringing us back to the inheritance example?

But, if on the one hand, the concepts of inheritance and exceptions are so deeply ingrained in our development process, and on the other hand, these concepts are alien to the WCF world, isn’t it terribly hard to write proper service-oriented applications? It is, unless you have framework support for bridging this gap.

In this article, we will look into managing an automatic bridge between the .NET exception-handling world and the service-oriented WCF error-handling paradigm, namely faults.

Faults at a Glance

A lot has been written in the past on the subject of WCF error handling, so I will only mention the basic principles. For more detailed information, consult the MSDN documentation or any good introductory text on WCF.

The underlying principle of service-oriented error handling consists of SOAP fault messages, which convey the failure semantics and additional information associated with the failure (such as the reason).

Most services which require error handling also require additional information to be passed with the error notification. This information can be transferred to the client as a standard WCF data contract, in the disguise of a fault. The contractual specification that a particular service operation can result in the specified fault is called a fault contract. The following code demonstrates a service operation contract that can result in the MyApplicationFault fault message:

[ServiceContract]
public interface IMyService {
    [OperationContract]
    [FaultContract(typeof(MyApplicationFault))]
    void MyMethod();
}

As far as the client is concerned, this is a contract — the service has just committed to only letting the MyApplicationFault fault message escape its boundaries. The client can now expect this fault message in his communication with the service.

Producing and Consuming Faults

The WCF service can produce a fault that is part of its fault contract, by throwing an exception. Throwing an exception is the most natural thing to do to indicate failure, for a .NET developer. The service is expected to throw the FaultException<TDetail> generic exception, with TDetail being the actual fault type that is being conveyed to the client. For example, the following service code conveys the MyApplicationFault fault to the client:

class MyService : IMyService {
    public void MyMethod() {
        MyApplicationFault fault = new MyApplicationFault(...);
        throw new FaultException<MyApplicationFault>(fault);
    }
}

Consuming the fault on the .NET client side is as simple as catching the FaultException. It’s possible to catch the non-generic FaultException base class, or any specific generic derivative. It’s also reasonable to expect communication- related exceptions that have nothing to do with the specific service implementation. For example, the following client code is a sensible way of calling the MyService service and catching the fault:

IMyService proxy = ...;    
try {
    proxy.MyMethod();
}
catch (CommunicationException) { ... }
catch (TimeoutException) { ... }
catch (FaultException<MyApplicationFault> myFault) {
    MyApplicationFault detail = myFault.Detail;
    
}
catch (FaultException otherFault) { ... }

This code defensively assumes that a communication problem might occur, a timeout might happen while waiting for the service call to complete, and a general unexpected fault might occur (other than the MyApplicationFault that is expected by the client).

What happens, though, if an unexpected exception escapes from the service side? Well, the client receives a non-generic FaultException that doesn’t convey too much information, and the client’s channel is faulted (it is possible to obtain more information on the fault by using ServiceBehavior.IncludeExceptionDetailInFaults, but it’s good for the debugging environment only — you don’t want to expose server stack traces to the outside world). All in all, it is not a friendly behavior, and should be avoided at all possible costs.

But, is it really so easy to avoid? Consider a typical service, that does a little more than just adding a couple of numbers together and returning the result. It probably calls into lots of downstream classes, which are by no means aware of the fact that they are being called by a specific service method, with a specific fault contract. Even if they were aware of it, coupling their implementation to the fault contract is a poor design decision, which decreases their general reusability. On the other hand, putting try...catch blocks inside every service call and deciding what fault message to return is a tedious task as well. This is another classic example of something we want the framework to perform on our behalf.

Error Handling Behavior

WCF has an excellent built-in extensibility mechanism for converting exceptions to faults. This extensibility point can be consumed through the IErrorHandler interface, which provides two methods: HandleError and ProvideFault. The HandleError method is called on a separate thread after the call has already completed, to possibly log the error and perform other book-keeping operations. It is useless in our scenario. The ProvideFault method, on the other hand, is called on the worker thread that is invoking the service call, and accepts the exception that was thrown by the service. It is expected to provide a fault message that will be sent to the client, and thus fits exactly what we are trying to accomplish. At runtime, an implementation of these methods can be hooked up to the ChannelDispatcher on the service side, and automatically get called whenever an unhandled exception escapes the service code.

We will begin with the core of the error handler. How do we decide what to do with the exception? Well, our first attempt could be converting any exception to a FaultException<TDetail> with TDetail as the exception type. For example, if an ArgumentException could be thrown from downstream code, then I should place the [FaultContract(typeof(ArgumentException))] attribute on my operation, and let the error handler convert the exception to a FaultException<ArgumentException> «fault». Considering that .NET exceptions are expected to be serializable, this is the minimal-effort path. On the other hand, a .NET exception type contains too much information that is only relevant on the service side. While easily achievable, this approach will reveal implementation details and contribute to the .NET- only fallacy.

To enforce stronger separation, we need a mapping mechanism between .NET exceptions and faults. While it is theoretically possible to establish such a mapping in a service-wide or even process-wide manner, it probably makes more sense to perform it in an operation-specific fashion. Like any operation-specific behavior, this is a good candidate for an attribute — so essentially, what we’re looking for is this kind of a syntax:

[ServiceContract]
public interface IMyService {
    [OperationContract]
    [FaultContract(typeof(MyApplicationFault))]
    [MapExceptionToFault(typeof(ApplicationException), typeof(MyApplicationFault))]
    void MyMethod();
}

What are we saying here? First of all, we’re specifying that the MyApplicationFault fault is part of the operation’s fault contract. Second, we’re specifying that whenever an ApplicationException exception is thrown, it should be converted to a MyApplicationFault fault. This is fairly easy to implement:

sealed class ErrorHandler : IErrorHandler {
    public void ProvideFault(Exception error,
                 MessageVersion version,
                 ref Message fault)
        {
            
            if (error is FaultException)
                return;

            
            OperationDescription operationDesc = ...;

            object faultDetail = GetFaultDetail(operationDesc.SyncMethod,
                        operationDesc.Faults,
                        error);
            if (faultDetail != null)
            {
                Type faultExceptionType =
                    typeof(FaultException<>).MakeGenericType(faultDetail.GetType());
                FaultException faultException =
                    (FaultException)Activator.CreateInstance(
            faultExceptionType, faultDetail, error.Message);
                MessageFault faultMessage = faultException.CreateMessageFault();
                fault = Message.CreateMessage(version,
                          faultMessage,
                          faultException.Action);
            }
        }

        private object GetFaultDetail(MethodInfo method,
        FaultDescriptionCollection faults,
            Exception error)
        {
            if (method != null)
            {
                MapExceptionToFaultAttribute[] mappers =
            (MapExceptionToFaultAttribute[])
                    method.GetCustomAttributes(
            typeof(MapExceptionToFaultAttribute), true);
                foreach (MapExceptionToFaultAttribute mapAttribute in mappers)
                {
                    if (mapAttribute.ExceptionType == error.GetType())
                    {
            
            
                        faultDetail =
                mapAttribute.GetFaultDetailForException(error);
                        if (faultDetail != null)
                        {
                            return faultDetail;
                        }
                    }
                }
            }
        
            foreach (FaultDescription faultDesc in faults)
            {
                if (faultDesc.DetailType == error.GetType())
                {
                   faultDetail = error;
                   break;
                }
            }
            return null;
        }
    
}

If no mapping attribute is present, the code automatically attempts to convert the exception into a fault, if the fault is part of the contract. If there is a mapping attribute present, then it is used to perform the conversion.

One of the tricky parts in writing the above code was getting the operation description for the currently executing service operation. Juval Lowy, in his «Programming WCF Services» book, parses the service type, looking for interface implementations and attributes on interface methods. I found an alternative, which uses the cleaner WCF API to find the currently executing operation:

OperationContext context = OperationContext.Current;
ServiceEndpoint endpoint =
    context.Host.Description.Endpoints.Find(
        context.EndpointDispatcher.EndpointAddress.Uri);
DispatchOperation dispatchOperation =
    context.EndpointDispatcher.DispatchRuntime.Operations.Where(
        op => op.Action == context.IncomingMessageHeaders.Action).First();
OperationDescription operationDesc =
    endpoint.Contract.Operations.Find(dispatchOperation.Name);

Installing the Error Handling Behavior

How do we go about installing this error handler on every channel dispatcher on our service? Well, it’s as simple as defining an attribute and implementing IServiceBehavior. Decorating our service class with this attribute will then install the error handler when the service host is opened. The following code demonstrates what the behavior needs to do:

public sealed class ErrorHandlingBehaviorAttribute : Attribute, IServiceBehavior
{
    public void ApplyDispatchBehavior(ServiceDescription serviceDescription,
        ServiceHostBase serviceHostBase)
    {
        foreach (ChannelDispatcherBase chanDispBase in
         serviceHostBase.ChannelDispatchers)
        {
            ChannelDispatcher channelDispatcher =
        chanDispBase as ChannelDispatcher;
            if (channelDispatcher == null)
                continue;
            channelDispatcher.ErrorHandlers.Add(new ErrorHandler(...));
        }
    }
    
}

This behavior can now be applied to a service implementation class:

[ErrorHandlingBehavior]
class MyService : IMyService ...

For completeness (to provide this behavior via configuration), a behavior extension element is required — but, this is one of the service traits that you will most often want to provide through code and not configuration.

Explicit Translation

The declarative model is not always sufficient for any service. Sometimes, the translation semantics must be specified only at runtime — something attributes cannot provide. One possible approach is to specify a type that augments the exception conversion process as part of the attribute placed on the service. We can define the following interface for external types to implement:

public interface IExceptionToFaultConverter
{
    object ConvertExceptionToFaultDetail(Exception error);
}

class MyServiceFaultProvider : IExceptionToFaultConverter
{
    public object ConvertExceptionToFaultDetail(Exception error)
    {
        if (error is ApplicationException)
            return new MyApplicationFault(...);
        return null;
    }
}

…and then specify the type that assists in the conversion as part of the attribute, when implementing the service:

[ErrorHandlingBehavior(
    ExceptionToFaultConverter=typeof(MyServiceFaultProvider))]
class MyService : IMyService ...

Adding support for this feature to the error handler itself is trivial (the necessary code is included as part of the source download for this article).

Summary

The approach outlined in this article allows service developers to focus on their business logic and call downstream facilities directly. It absolves service developers from the need to worry about letting only permitted faults escape the service boundary, and provides a convenient mechanism for mapping .NET exceptions to well-defined WCF faults.

History

  • Version 1 — May 24th, 2008
description title ms.date ms.assetid

Learn more about: Error handling in Windows Communication Foundation (WCF)

Error handling

03/30/2017

c948841a-7db9-40ae-9b78-587d216cbcaf

Error handling in Windows Communication Foundation (WCF)

When a service encounters an unexpected exception or error, there are multiple ways to design an exception-handling solution. While there is no single «correct» or «best practice» error-handling solution, there are multiple valid paths for one to consider. It is normally recommended that one implement a hybrid solution that combines multiple approaches from the list below, depending on the complexity of the WCF implementation, the type and frequency of the exceptions, the handled vs. unhandled nature of the exceptions, and any associated tracing, logging, or policy requirements.

These solutions are explained more deeply in the rest of this section.

The Microsoft Enterprise Library

The Microsoft Enterprise Library Exception Handling Application Block helps implement common design patterns and create a consistent strategy for processing exceptions that occur in all architectural layers of an enterprise application. It is designed to support the typical code contained in catch statements in application components. Instead of repeating this code (such as code that logs exception information) in identical catch blocks throughout an application, the Exception Handling Application Block allows developers to encapsulate this logic as reusable exception handlers.

This Library includes out-of-the-box a Fault Contract Exception Handler. This exception handler is designed for use at WCF service boundaries, and generates a new Fault Contract from the exception.

Application blocks aim to incorporate commonly used best practices and provide a common approach for exception handling throughout your application. On the other hand, custom error handlers and fault contracts developed on one’s own can also be very useful. For instance, custom error handlers provide an excellent opportunity to automatically promote all exceptions to FaultExceptions and also to add logging capabilities to your application.

For more information, please see Microsoft Enterprise Library.

Dealing with expected exceptions

The proper course of action is to catch expected exceptions in every operation or relevant extensibility point, decide whether they can be recovered from, and return the proper custom fault in a FaultException<T>.

Dealing with unexpected exceptions using an IErrorHandler

To deal with unexpected exceptions, the recommended course of action is to «hook» an IErrorHandler. Error handlers only catch exceptions at the WCF runtime level (the «service model» layer), not at the channel layer. The only way to hook an IErrorHandler at the channel level is to create a custom channel, which is not recommended in most scenarios.

An «unexpected exception» is generally neither an irrecoverable exception nor a processing exception; it is, instead, an unexpected user exception. An irrecoverable exception (such as an out-of-memory exception) – one generally handled by the Service Model Exception Handler automatically – cannot generally be handled gracefully, and the only reason to handle such an exception at all may be do additional logging or to return a standard exception to the client. A processing exception occurs in the processing of the message – for example, at the serialization, encoder, or formatter level – generally cannot be handled at an IErrorHandler, because it is generally either too early or too late for the error handler to intervene by the time these exceptions occur. Similarly, transport exceptions cannot be handled at an IErrorHandler.

With an IErrorHandler, you can explicitly control the behavior of your application when an exception is thrown. You may:

  1. Decide whether or not to send a fault to the client.

  2. Replace an exception with a fault.

  3. Replace a fault with another fault.

  4. Perform logging or tracing.

  5. Perform other custom activities.

One can install a custom error handler by adding it to the ErrorHandlers property of the channel dispatchers for your service. It is possible to have more than one error handler and they are called in the order they are added to this collection.

IErrorHandler.ProvideFault controls the fault message that is sent to the client. This method is called regardless of the type of the exception thrown by an operation in your service. If no operation is performed here, WCF assumes its default behavior and continues as if there were no custom error handlers in place.

One area that you could perhaps use this approach is when you want to create a central place for converting exceptions to faults before they are sent to the client (ensuring that the instance is not disposed and the channel is not moved to the Faulted state).

The IErrorHandler.HandleError method is usually used to implement error-related behaviors such as error logging, system notifications, shutting down the application, etc. IErrorHandler.HandleError can be called at multiple places inside the service, and depending on where the error is thrown, the HandleError method may or may not be called by the same thread as the operation; no guarantees are made in this regard.

Dealing with exceptions outside WCF

Often, configuration exceptions, database connection string exceptions, and other similar exceptions may occur within the context of a WCF application, but are themselves are not exceptions caused by the service model or the web service itself. These exceptions are «regular» exceptions external to the web service, and should be handled just as other external exceptions in the environment are to be handled.

Tracing exceptions

Tracing is the only «catch-all» place where one can potentially see all exceptions. For more information on tracing and logging exceptions, see Tracing and Logging.

URI template errors when using WebGetAttribute and WebInvokeAttribute

The WebGet and WebInvoke attributes allow you to specify a URI template that maps components of the request address to operation parameters. For example, the URI template «weather/{state}/{city}» maps the request address into literal tokens, a parameter named state, and a parameter named city. These parameters might then be bound by name to some of the formal parameters of the operation.

The template parameters appear in the form of strings within the URI while the formal parameters of a typed contract might be of non-string types. Therefore, a conversion needs to take place before the operation can be invoked. A table of conversion formats is available.

However, if the conversion fails, then there’s no way to let the operation know that something has gone wrong. The type conversion instead surfaces in the form of a dispatch failure.

A type conversion dispatch failure can be inspected the same as with many other types of dispatch failures by installing an error handler. The IErrorHandler extensibility point is called to handle service-level exceptions. From there, the response to be sent back to the caller – as well as perform any custom tasks and reporting – may be chosen.

See also

  • Basic WCF Programming

What If There’s No Error Handling?

Suppose I write a WCF web service with no try-catch blocks and no error handling. What happens when my web service throws an exception? Since I don’t have any error handling, WCF catches the exception for me. It sends the client (the program that called my web service) a FaultException with the following message:

«The server was unable to process the request due to an internal error.»

Whenever there’s an unhandled exception, that’s all the information the client gets. WCF doesn’t send the client the exception message or the stack trace or any of the other information that was contained in the exception.

There are a number of reasons why WCF does this. One reason is that the Exception class is specific to .Net. WCF was designed to make web services that can be called by anyone, including clients that are not written in .Net. The client program can be written in Java or PHP or a variety of other languages. So WCF doesn’t assume that the clients were written in .Net, and it doesn’t send them .Net specific responses.

Another reason WCF doesn’t send the client more information is that this might not be safe. It’s not safe to provide the stack trace to anyone that may call. Detailed error messages are also risky. For example, it’s not safe to inform the caller that the database insert failed because user name «andrew.fenster» is already in use. The safer practice is to write this information to an error log and provide much less detailed error information to the caller.

Providing More Information With FaultExceptions

A bare FaultException may be safe, but it doesn’t provide enough information. I may not want to pass the full stack trace, but I want to provide at least basic information about what went wrong. WCF provides multiple ways to do this.

The FaultException class itself includes several ways to provide more information. The FaultException class includes these constructors (among others):

  1. public FaultException(string reason);  
  2. public FaultException(string reason, FaultCode code);  
  3. public FaultException(FaultReason reason);  
  4. public FaultException(FaultReason reason, FaultCode code);  

The simplest way to provide information is the first of these:

  1. try  
  2. {  
  3.       
  4. }  
  5. catch (Exception ex)  
  6. {  
  7.      myLogger.LogException(ex);  
  8.      throw new FaultException(«Your request timed out. Please try again later.»);  
  9. }  

The client can capture the FaultException and read the message as follows:

  1. try  
  2. {  
  3.        
  4. }  
  5. catch (FaultException ex)  
  6. {  
  7.      Console.WriteLine(ex.Message);  
  8. }  

As you can see from the FaultException constructors, you can create a FaultException with a string, a FaultCode, a FaultReason or some combination of these.

The FaultReason class lets you provide the same error message in multiple languages. If you look at the list of FaultException constructors, you will see that you can either provide an error message in a string or a collection of error messages in a FaultReason. You don’t need both.

A FaultCode allows you to provide a code (a string) to tell the client what went wrong. For example:

  1. try  
  2. {  
  3.         
  4. }  
  5. catch (Exception ex)  
  6. {  
  7.      myLogger.LogException(ex);  
  8.      FaultCode code = new FaultCode(«Invalid Operation»);  
  9.      throw new FaultException(«Customer name cannot be null.», code);  
  10. }  

The client can catch the FaultException and read the FaultCode as follows:

  1. try  
  2. {  
  3.        
  4. }  
  5. catch (FaultException ex)  
  6. {  
  7.      Console.WriteLine(«FaultCode: « + ex.Code);  
  8.      Console.WriteLine(«Message: « + ex.Message);  
  9. }  

The FaultException<T> class

The FaultException class gives you several ways to inform the client about what went wrong. Sometimes, however, you may want more.

The FaultException<T> class is derived from the FaultException class. As with the FaultException class, you can pass in some combination of string, FaultCode and FaultReason. You can also pass in some additional value T. T can be a value or an entire class object. For example, you could define your own error class:

  1. [DataContract]  
  2. public class ErrorMessage  
  3. {  
  4.       private Guid ticketNumber;  
  5.        [DataMember]  
  6.       public Guid TicketNumber  
  7.       {  
  8.            get { return ticketNumber; }  
  9.            set { ticketNumber = value; }  
  10.       }  
  11.   
  12.       [DataMember]  
  13.       public string Message  
  14.       {  
  15.            get { return «An error has occurred. For more information,   
  16.                              call us and tell us your ticket number.»; }  
  17.       }      public ErrorMessage(Guid newTicket)  
  18.       {  
  19.            ticketNumber = newTicket;  
  20.       }  
  21. }  

You could use this as follows:

  1. try  
  2. {  
  3.         
  4. }  
  5. catch (Exception ex)  
  6. {  
  7.       Guid ticket = myLogger.LogException(ex);         
  8.       ErrorMessage message = new ErrorMessage(ticket);  
  9.       throw new FaultException<ErrorMessage>(message);  
  10. }  

The client can catch this FaultException as follows:

  1. try  
  2. {  
  3.         
  4. }  
  5. catch (FaultException<ErrorMessage> ex)  
  6. {  
  7.       Guid ticket = ex.Detail.TicketNumber;  
  8.       string message = ex.Detail.Message;  
  9. }  

Of course you could also throw in a FaultCode or a FaultReason, since FaultException<T> is derived from FaultException. FaultException<T> includes these constructors:

  1. public FaultException(T detail);  
  2. public FaultException(T detail, string reason);  
  3. public FaultException(T detail, FaultReason reason);  
  4. public FaultException(T detail, string reason, FaultCode code);  
  5. public FaultException(T detail, FaultReason reason, FaultCode code);  

When you use the FaultException<T> class, T can be any type, provided in can be serialized. If you are going to use your own custom class, you should define a DataContract for your class, as shown above.

FaultContracts

If you are going to use the FaultException<T> class, you need to create a FaultContract. The FaultContract tells the client program what type of Faults each method can throw. For example:

  1. [ServiceContract]  
  2. interface IMyService  
  3. {  
  4.     [OperationContract]  
  5.     [FaultContract(typeof(ErrorMessage))]  
  6.     int DoSomething();  
  7. }  

This FaultContract informs the client that when it calls DoSomething( ) it may receive a fault of type FaultException<ErrorMessage>.

You can specify more than one fault type. For example:

  1. [ServiceContract]  
  2. interface IMyService  
  3. {  
  4.      [OperationContract]  
  5.      [FaultContract(typeof(ErrorMessage))]  
  6.      [FaultContract(typeof(Guid))]  
  7.      int DoSomething();  
  8. }  

Now my method can throw either FaultException<ErrorMessage> or FaultException<Guid>.

If a web service throws a FaultExeption<T> of a type not declared in the ServiceContract, it will not reach the client. For example, if the ServiceContract says I will throw a FaultException<ErrorMessage>, and my service instead throws a FaultException<string>, WCF will block my fault. Instead, it will send the client a bare FaultException with the generic message «The server was unable to process the request due to an internal error.»

Best Practices

There are no shortage of people offering their own advice about error handling. I have only a few points to make.

First and most important, you should be very cautious about providing detailed information to the client about what went wrong. Most error details are either a security risk or simply irrelevant to the client. For example, the Stack Trace contains details about your code which should not be revealed. Even if the client is another division within your own company, they don’t need you to send them the Stack Trace. If you sent them the Stack Trace, what would they do with it? Likewise, it’s not a good idea to simply catch exceptions and pass the exception Message to the client.

There are only a few types of messages that the client may care about. For example, if the client did not provide a required field, informing the client might be useful. If the system is down temporarily, you could tell the client to try later. Error messages that reveal details about your code, however, don’t help the client but do provide security risks.

Using an ErrorMessage class like the one shown above may be sufficient. The client is informed that something went wrong. It anyone needs more information, they can provide you with a ticket number, and you can look up the error in the error log.

One other suggestion: if you are going to provide any significant error information, it would be best to have a FaultContract. Even though the basic FaultException class allows you to pass a message and a FaultCode and a FaultReason (and a few other things not discussed in this article), it makes sense to forego these and use a FaultException<T>, with all your error information inside the detail object T. That way the client knows exactly what to expect and doesn’t try reading a value from the FaultReason when there’s no FaultReason provided.

In conclusion, WCF provides you with a lot of options for error handling. As long as you think carefully about what information you are providing and the format in which you provide it, you should come out fine.

I have project in which i am calling soap based service . I am using fault and communication exception as mostly two of these exception occurs in calling of api. but what if any other exception occurs instead of these two exception in soap api ?

    try
    {
      //soap api
    }
    catch(FaultException ex)
    {
    }
    catch(CommunicationException ex)
    {
    }

Later on i read on internet about soap exception class. and i am considering to change my code like :

     try
    {
      //soap api
    }

    catch(SoapException ex)
    {
    }

Now what i need to know is if i use Soap Exception instead of fault and communication exception . would it be good ? all i need is the catch the exception if it occurs in soap api. however i want to know does the soap api also handles the fault and communication exception or i have to explicitly define my code like ?

 try
    {
      //soap api
    }
    catch(FaultException ex)
    {
    }
    catch(CommunicationException ex)
    {
    }
    catch(SoapException ex)
    {
    }

asked Jan 2, 2014 at 6:13

shujaat siddiqui's user avatar

shujaat siddiquishujaat siddiqui

1,4671 gold badge19 silver badges40 bronze badges

As stated on MSDN:

The errors encountered by a WCF application belong to one of three
groups:

  • Communication Errors
  • Proxy/Channel Errors
  • Application Errors

Communication errors occur when a network is unavailable, a client uses an incorrect address, or the service host is not listening for
incoming messages. Errors of this type are returned to the client as
CommunicationException or CommunicationException-derived classes.

Proxy/Channel errors are errors that occur within the channel or proxy itself. Errors of this type include: attempting to use a proxy
or channel that has been closed, a contract mismatch exists between
the client and service, or the client’s credentials are rejected by
the service. There are many different types of errors in this
category, too many to list here. Errors of this type are returned to
the client as-is (no transformation is performed on the exception
objects).

Application errors occur during the execution of a service operation. Errors of this kind are sent to the client as
FaultException or FaultException<TDetail>.

Error handling in WCF is performed by one or more of the following:

  • Directly handling the exception thrown. This is only done for communication and proxy/channel errors.
  • Using fault contracts
  • Implementing the IErrorHandler interface
  • Handling ServiceHost events

Fault Contracts Fault contracts allow you to define the errors that can occur during service operation in a platform independent way.
By default all exceptions thrown from within a service operation will
be returned to the client as a FaultException object. The
FaultException object will contain very little information. You can
control the information sent to the client by defining a fault
contract and returning the error as a FaultException. For more
information, see Specifying and Handling Faults in Contracts and
Services.

IErrorHandler The IErrorHandler interface allows you more control over how your WCF application responds to errors. It gives you full
control over the fault message that is returned to the client and
allows you to perform custom error processing such as logging. For
more information, see IErrorHandler and Extending Control Over Error
Handling and Reporting

ServiceHost Events The ServiceHost class hosts services and defines several events that may be needed for handling errors. For
example:

1.Faulted

2.UnknownMessageReceived

You can also refer to a similar question, which has many good answers as well:
What is the best approach to handle exceptions in WCF service?

Community's user avatar

answered Jan 2, 2014 at 6:22

Pranav Singh's user avatar

Pranav SinghPranav Singh

15.7k28 gold badges79 silver badges102 bronze badges

1

If you have the timeline to create a nice set of custom Exceptions extending from ClientSafeException then I would divide those up between client friendly exceptions and non-client friendly exceptions.

catch (ClientSafeException safeException)
{
    response.ServiceResponse= ExceptionHandler.ProcessSafeExceptionResponse(safeException);
     request.Succeeded = false;
}
catch (Exception unsafeException)
{
    response.ServiceResponse= ExceptionHandler.ProcessUnsafeExceptionResponse(unsafeException);
    request.Succeeded = false;
}
LogServiceResponse(request, response.ServiceResponse);

return response;

Sorry to not mention that the static ExceptionHandler class routes safe vs. non-safe client exceptions.

Fernando Carvalhosa's user avatar

answered Jan 2, 2014 at 6:27

Ross Bush's user avatar


.NET Framework 4

The errors encountered by a WCF application belong to one of three groups:

  1. Communication Errors
  2. Proxy/Channel Errors
  3. Application Errors

Communication errors occur when a network is unavailable, a
client uses an incorrect address, or the service host is not listening
for incoming messages. Errors of this type are returned to the client as
CommunicationException or CommunicationException-derived classes.

Proxy/Channel errors are errors that occur within the channel or
proxy itself. Errors of this type include: attempting to use a proxy or
channel that has been closed, a contract mismatch exists between the
client and service, or the client’s credentials are rejected by the
service. There are many different types of errors in this category, too
many to list here. Errors of this type are returned to the client as-is
(no transformation is performed on the exception objects).

Application errors occur during the execution of a service operation. Errors of this kind are sent to the client as FaultException or FaultException.

Error handling in WCF is performed by one or more of the following:

  • Directly handling the exception thrown. This is only done for communication and proxy/channel errors.
  • Using fault contracts
  • Implementing the IErrorHandler interface
  • Handling ServiceHost events

Fault Contracts

Fault contracts allow you to define the errors that can occur
during service operation in a platform independent way. By default all
exceptions thrown from within a service operation will be returned to
the client as a FaultException object. The FaultException
object will contain very little information. You can control the
information sent to the client by defining a fault contract and
returning the error as a FaultException. For more information, see Specifying and Handling Faults in Contracts and Services.

IErrorHandler

The IErrorHandler interface allows you more
control over how your WCF application responds to errors. It gives you
full control over the fault message that is returned to the client and
allows you to perform custom error processing such as logging. For more
information, see IErrorHandler and Extending Control Over Error Handling and Reporting

ServiceHost Events

The ServiceHost class hosts services and defines several events that may be needed for handling errors. For example:

  1. Faulted
  2. UnknownMessageReceived

For more information see below

WCF Service Host (WcfSvcHost.exe)


.NET Framework 4

Other Versions

Windows Communication Foundation (WCF) Service Host (WcfSvcHost.exe)
allows you to launch the Visual Studio debugger (F5) to automatically
host and test a service you have implemented. You can then test the
service using WCF Test Client (WcfTestClient.exe), or your own client,
to find and fix any potential errors.

WCF Service Host

WCF Service Host enumerates the services in a WCF service project,
loads the project’s configuration, and instantiates a host for each
service that it finds. The tool is integrated into Visual Studio through
the WCF Service template and is invoked when you start to debug your
project.

By using WCF Service Host, you can host a WCF service (in a WCF
service library project) without writing extra code or committing to a
specific host during development.

Bb552363.note(en-us,VS.100).gifNote:
WCF Service Host does not support Partial Trust. If you want to use a
WCF Service in Partial Trust, do not use the WCF Service Library Project
template in Visual Studio to build your service. Instead, create a New
WebSite in Visual Studio by choosing the WCF Service WebSite template,
which can host the service in a WebServer on which WCF Partial Trust is
supported.

Project Types hosted by WCF Service Host

WCF Service Host can host the following WCF service library project
types: WCF Service Library, Sequential Workflow Service Library, State
Machine Workflow Service Library and Syndication Service Library. WCF
Service Host can also host those services that can be added to a service
library project using the Add Item functionality. This
includes WCF Service, WF State Machine Service, WF Sequential Service,
XAML WF State Machine Service and XAML WF Sequential Service.

You should note, however, that the tool will not help you to
configure a host. For this task, you must manually edit the App.config
file. The tool also does not validate user-defined configuration files.

Bb552363.Caution(en-us,VS.100).gifCaution:
You should not use WCF Service Host to host services in a production
environment, as it was not engineered for this purpose. WCF Service
Host does not support the reliability, security, and manageability
requirements of such an environment. Instead, use IIS since it provides
superior reliability and monitoring features, and is the preferred
solution for hosting services. Once development of your services is
complete, you should migrate the services from WCF Service Host to IIS.

Scenarios for Using WCF Service Host inside Visual Studio

The following table lists all the parameters in the Command line arguments dialog box, which can be found by right-clicking your project in Solutions Explorer in Visual Studio, selecting Properties, then selecting the Debug tab and clicking Start Project. These parameters are useful in configuring WCF Service Host.

Parameter Meaning

/client

An optional parameter that specifies the path to an executable to run
after the services are hosted. This launches WCF Test Client following
hosting.

/clientArg

Specify a string as an argument that is passed to the custom client application.

/?

Displays the help text.

Using WCF Test Client

After you create a new WCF service project and press F5 to start the
debugger, WCF Service Host starts hosting all the services it finds in
your project. WCF Test Client automatically opens and displays a list of
service endpoints defined in the configuration file. From the main
window, you can test the parameters and invoke your service.

To make sure that WCF Test Client is used, right-click your project in Solutions Explorer in Visual Studio, select Properties, then select the Debug tab. Click Start Project and ensure that the following appears in the Command line arguments dialog box.

/client:WcfTestClient.exe

Using a Custom Client

To use a custom client, right-click your project in Solutions Explorer in Visual Studio, select Properties, then select the Debug tab. Click Start Project and edit the /client parameter in the Command line arguments dialog box to point to your custom client, as indicated in the following example.

/client:"path/CustomClient.exe"

When you press F5 to start the service again, WCF Service Host
automatically starts your custom client when you launch the debugger.

You can also use the /clientArg: parameter to specify a
string as an argument that is passed to the custom client application,
as indicated in the following example.

/client:"path/CustomClient.exe" /clientArg:"arguments that are passed to Client"

For example, if you are using the Syndication Service Library template, you can use the following command line arguments,

/client:iexplore.exe /clientArgs:http://localhost:8731/Design_Time_Addresses/Feed1/

Specifying No Client

To specify that no client will be used after WCF service hosting, right-click your project in Solutions Explorer in Visual Studio, select Properties, then select the Debug tab. Click Start Project and leave the Command line arguments dialog box blank.

Using a Custom Host

To use a custom host, right-click your project in Solutions Explorer in Visual Studio, select Properties, then select the Debug tab. Click Start External Program and enter the full path to the custom host. You can also use the Command line arguments dialog box to specify arguments to be passed to the host.

WCF Service Host User Interface

When you initially invoke WCF Service Host (by pressing F5 inside Visual Studio), the WCF Service Host
window automatically opens. When WCF Service Host is running, the
program’s icon appears in the notification area. Double-click the icon
to open the WCF Service Host window

When errors occur during service hosting, WCF Service Host dialog box will open to display relevant information.

The WCF Service Host main window contains two menus:

  • File: Contains the Close and Exit commands. When you click Close, the WCF Service Host dialog box closes, but the services continue to be hosted. When you click Exit, WCF Service Host is also shut down. This also stops all hosted services.
  • Help: Contains the About command that contains version information. It also contains the Help command that can open a help file.

The main WCF Service Host window contains two areas:

  • The first area is Service. It contains a list that displays basic information of all services. The information includes:

    • Service: Lists all the services.
    • Status: Lists the status of the service. Valid values are «Started”, “Stopped,” and “Error”.
    • Metadata Address: Displays the metadata address of the services.
  • The second area is Additional Information. It displays a detailed explanation of the service status when the specific service line is selected in the Service area. If the status is Error, you can view the full error message on the screen.

Stopping WCF Service Host

You can shut down WCF Service Host in the following four ways:

  • Stop the debugging session in Visual Studio.
  • Select Exit from the File menu in the WCF Service Host window.
  • Select Exit from context menu of WCF Service Host tray icon in the system notification area.
  • Exit WCF Test Client if it is being used.

Using Service Host without Administrator privilege

To enable users without administrator privilege to develop WCF
services, an ACL (Access Control List) is created for the namespace
«http://+:8731/Design_Time_Addresses» during the installation of Visual
Studio. The ACL is set to (UI), which includes all interactive users
logged on to the machine. Administrators can add or remove users from
this ACL, or open additional ports.This ACL enables users to use the WCF
Service Auto Host (wcfSvcHost.exe) without granting them administrator
privileges.

You can modify access using the netsh.exe tool in Windows Vista under
the elevated administrator account. The following is an example of
using netsh.exe.

netsh http add urlacl url=http://+:8001/MyService user=<domain><user>

For more information on netsh.exe, see «How to Use the Netsh.exe Tool and Command-Line Switches».

Давайте поговорим про передачу исключений через WCF сервис.

Для начала давайте представим ситуацию – у нас есть метод RegisterUser, который соответственно производит регистрацию пользователя. И в случае ошибки в вводе каких-либо данных кидает CustomException.
Выглядит код регистрации примерно так:

/// <summary>  
/// Registers the user.  
/// </summary>  
/// <param name="username">The username.</param>  
/// <param name="password">The password.</param>  
/// <param name="email">The email.</param>  
public void RegisterUser(string username, string password, string email)  
{  
    if (/*проверяем username*/)  
        throw new InvalidUsernameException();  
    if (/*проверяем password*/)  
        throw new InvalidPasswordException();  
    if (/*проверяем email*/)  
        throw new InvalidEmailException();
    ...  
}
* This source code was highlighted with Source Code Highlighter.

А так его использование:

/// <summary>  
/// Handles the Click event of the btnRegister control.  
/// </summary>  
/// <param name="sender">The source of the event.</param>  
/// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>  
protected void btnRegister_Click(object sender, EventArgs e)  
{  
    try  
    {  
        RegisterUser(txtUsernamt.Text, txtPassword.Text, txtEmail.Text);  
    }  
    catch (InvalidUsernameException usernameException)  
    {  
        // даем знать пользователю произошла ошибка связанная с Username  
    }  
    catch (InvalidPasswordException passwordException)  
    {  
        // даем знать пользователю произошла ошибка связанная с Password  
    }  
    catch (InvalidEmailException emailException)  
    {  
        // даем знать пользователю что произошла ошибка связанная с Email  
    }  
    ...  
* This source code was highlighted with Source Code Highlighter.

 

Всё отлично работает, программист знает как обработать ошибку, пользователь знает где ошибка.
А теперь представим, что метод RegisterUser у нас находится в WCF сервисе.
Вот что говорит MSDN по поводу исключений в WCF:

In all managed applications, processing errors are represented by Exception objects. In SOAP-based applications such as WCF applications, service methods communicate processing error information using SOAP fault messages. SOAP faults are message types that are included in the metadata for a service operation and therefore create a fault contract that clients can use to make their operation more robust or interactive. In addition, because SOAP faults are expressed to clients in XML form, it is a highly interoperable type system that clients on any SOAP platform can use, increasing the reach of your WCF application.

Это означает, что для передачи исключения используется SOAP fault message и с ними надо работать несколько иначе.
Т.е. мы можем бросать только FaultException.
Но не все так скучно, у FaultException есть generic перегрузка FaultException<T>. Ей мы и воспользуемся.

 
Создадим специальные классы для наших ошибок:

/// <summary>  
///  указывает на ошибку в Username  
/// </summary>
[DataContract]  
class InvalidUsernameFault  
{  
    [DataMember]  
    public string CustomError;
    public InvalidUsernameFault()  
    {  
    }
    public InvalidUsernameFault(string error)  
    {  
        CustomError = error;  
    }  
}
 /// <summary> 
///  указывает на ошибку в Password 
/// </summary>  [DataContract]  
class InvalidPasswordFault  
{  
    [DataMember]  
    public string CustomError;
    public InvalidPasswordFault()  
    {  
    }
    public InvalidPasswordFault(string error)  
    {  
        CustomError = error;  
    }  
}/// <summary>  
///  указывает на ошибку в Email  
/// </summary>
[DataContract]  
class InvalidEmailFault  
{  
    [DataMember]  
    public string CustomError;
    public InvalidEmailFault()  
    {  
    }
    public InvalidEmailFault(string error)  
    {  
        CustomError = error;  
    }  
}
* This source code was highlighted with Source Code Highlighter.

 

Теперь вернемся к нашему WCF сервису.
В интерфейсе мы должны указать FaultContract для нашего метода:

[OperationContract]
[FaultContract(typeof(InvalidUsernameFault))]
[FaultContract(typeof(InvalidPasswordFault))]
[FaultContract(typeof(InvalidEmailFault))]
void RegisterUser(string username, string password, string email);
* This source code was highlighted with Source Code Highlighter.

Ну а теперь мы может быть уверены что наши исключения дойдут до клиента:

/// <summary>  
/// Registers the user.  
/// </summary>  
/// <param name="username">The username.</param>  
/// <param name="password">The password.</param>  
/// <param name="email">The email.</param>  
public void RegisterUser(string username, string password, string email)  
{  
    if (/*проверяем username*/)  
        throw new FaultException<InvalidUsernameFault>(new InvalidUsernameFault());  
    if (/*проверяем password*/)  
        throw new FaultException<InvalidPasswordFault>(new InvalidPasswordFault());  
    if (/*проверяем email*/)  
        throw new FaultException<InvalidEmailFault>(new InvalidEmailFault());
    ...  
}Или можно бросать FaultException указывая подробное описание ошибки. Удобно, например для логгирования:/// <summary>  
/// Registers the user.  
/// </summary>  
/// <param name="username">The username.</param>  
/// <param name="password">The password.</param>  
/// <param name="email">The email.</param>  
public void RegisterUser(string username, string password, string email)  
{  
    if (/*проверяем username*/)  
        throw new FaultException<InvalidUsernameFault>(new InvalidUsernameFault(“пользователь Medved уже зарегистрирован”));  
    if (/*проверяем password*/)  
        throw new FaultException<InvalidPasswordFault>(new InvalidPasswordFault(“пароль ’12345’ недопустим”));  
    if (/*проверяем email*/)  
        throw new FaultException<InvalidEmailFault>(new InvalidEmailFault(“уже зарегистрирован пользователь с адресом ya@krasafcheg.ru”));
    ...  
}
* This source code was highlighted with Source Code Highlighter.

 
Обрабатывать такие исключения тоже проще простого:

/// <summary>  
/// Handles the Click event of the btnRegister control.  
/// </summary>  
/// <param name="sender">The source of the event.</param>  
/// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>  
protected void btnRegister_Click(object sender, EventArgs e)  
{  
    try  
    {
        … 
        wcfclient.RegisterUser(txtUsernamt.Text, txtPassword.Text, txtEmail.Text);  
    }  
    catch (FaultException<InvalidUsernameFault> usernameException)  
    {  
        // даем знать пользователю произошла ошибка связанная с Username  
    }  
    catch (FaultException<InvalidPasswordFault> passwordException)  
    {  
        // даем знать пользователю произошла ошибка связанная с Password  
    }  
    catch (FaultException<InvalidEmailFault> emailException)  
    {  
        // даем знать пользователю что произошла ошибка связанная с Email  
    }
    catch (FaultException faultEx)  
    {  
        // обрабатывает нераспознанную ошибку, например произошла ошибка авторизации или
        // ошибка соединения с сервером нашего WCF сервиса 
    }     ...  
}

* This source code was highlighted with Source Code Highlighter.

 

Как видим, ничего сложного нет! Есть вопросы? напишите, обязательно разберемся ;-)
Hope this helps!
Кросспост

We can easily customize the FaultContract with generic version FaultContract<T>
which helps you to provide more appropriate and meaningful details to clients with
custom error messages and also the flexibility to log or take actions on critical
errors. To get more details about exceptions you can enable WCF tracing and logging.

Why we should use the FaultContract rather than using .Net exceptions?

Exceptions have limitations and security risks.

  1. .Net exception can be used by only CLR supported languages so losing great WCF
    feature of interoperability.
  2. Throwing exceptions can provide service implementation and private details to clients.
  3. Exceptions are tightly coupled between clients and service.

Walkthrough for implementing FaultContracts.

  1. Create WCF Service library

    Create a new WCF Service library as suggested in Create new WCF service library and test using WCFTestClient. This article
    will give you a basic service implementation.

  2. Add DataContract for FaultContract

    Add new DataContract
    which will work as FaultContract to send error messages to clients.

                
    [DataContract]
    public class ServiceException
    {
        /// <summary>
        /// Exception Message
        /// </summary>
        [DataMember]
        public string Message { get; set; }
    
        /// <summary>
        /// If critical, user should redirect to error page 
        /// and exception details should log.
        /// </summary>
        [DataMember]
        public bool IsCritical { get; set; }
    }
                 

    See details about DataMember and EnumMember.

  3. Exception Manager

    Add a new sealed class to the project and name it as ExceptionManager.
    This class will work as a single point to handle all WCF service exceptions and errors.

                
    public sealed class ExceptionManager
    {
        /// <summary>
        /// Private Constructor to ensure that the class cannot be instantiated
        /// </summary>
        private ExceptionManager()
        {
    
        }
    
        public static ServiceException HandleException(string message)
        {
            return HandleException(message, false); 
        }
    
        public static ServiceException HandleException(string message,
                                                            bool isCritical)
        {
            ServiceException exception = new ServiceException();
            exception.Message = message;
            exception.IsCritical = isCritical; 
    
            // Log exception details if it is critical
    
            return exception;
        }
    
        public static ServiceException HandleException(System.Exception ex)
        {
            ServiceException exception = new ServiceException();
            exception.Message = ex.Message;
            exception.IsCritical = IsCritical(ex);
                
            // Log exception details if it is critical
    
            return exception;
        }
    
        /// <summary>
        /// If error is not user defined then IsCritical should be true.
        /// </summary>
        /// <param name="ex">Exception</param>
        /// <returns>bool value</returns>
        private static bool IsCritical(System.Exception ex)
        {
            bool returnValue = true;
            if (ex is SqlException)
            {
                SqlException sqlEx = (SqlException)ex;
                returnValue = sqlEx.Number > 50000 ? false : true; 
            }
            return returnValue;
        }
    
        public static bool HandleException(System.Exception ex, string policyName)
        {
            throw new NotImplementedException();
        }
    }
                
  4. Add FaultContracts

    Add FaultContracts to OperationContract.

                
    [ServiceContract]
    public interface IProducts
    {
        [OperationContract]
                [FaultContract(typeof(ServiceException))]
        string GetProductName(int productID);
    
        [OperationContract]
                [FaultContract(typeof(ServiceException))]
        int GetProductQty(int productID);
    
        [OperationContract]
                [FaultContract(typeof(ServiceException))]
        string GetCategoryName(int productID);
    }       
                            
                
  5. FaultContract Implementation

    Add implementation for FaultContract. If any error occurs, an error will be handled by ExceptionManager class and a custom message will be returning to clients.

                
    public class ProductService : IProducts
    {
    public string GetProductName(int productID)
    {
        string productName = string.Empty;
    
        try
        {
            XDocument doc = XDocument.Load("products.xml");
    
            productName =
                (from result in doc.Descendants("DocumentElement")
                .Descendants("Products")
                where result.Element("productID").Value == productID.ToString()
                select result.Element("productname").Value)
                .FirstOrDefault<string>();
    
                if (string.IsNullOrEmpty(productName)) 
                    throw new FaultException<ServiceException>(ExceptionManager.
                        HandleException("Product ID does not exist in system.")); 
        }catch (Exception ex) 
        { 
            throw new FaultException<ServiceException> 
                (ExceptionManager.HandleException(ex));
        }
    
        return productName;
    }
            
    public int GetProductQty(int productID)
    {   
        int ProductQty = 0;
    
        try
        {
            XDocument doc = XDocument.Load("products.xml");
            string strProductQty =
                (from result in doc.Descendants("DocumentElement")
                .Descendants("Products")
                where result.Element("productID").Value == productID.ToString()
                select result.Element("UnitsInStock").Value)
                .FirstOrDefault<string>();
    
                 if (string.IsNullOrEmpty(strProductQty)) 
                    throw new FaultException<ServiceException>(ExceptionManager.
                        HandleException("Product ID does not exist in system.")); 
    
            int.TryParse(strProductQty, out ProductQty);
        }catch (Exception ex) 
        { 
            throw new FaultException<ServiceException>
                    (ExceptionManager.HandleException(ex));
        } 
        return ProductQty;
    }
    
    public string GetCategoryName(int productID)
    {
        string categoryName = string.Empty;
        try
        {
            XDocument doc = XDocument.Load("products.xml");
    
            categoryName =
                (from result in doc.Descendants("DocumentElement")
                .Descendants("Products")
                where result.Element("productID").Value == productID.ToString()
                select result.Element("CategoryName").Value)
                .FirstOrDefault<string>();
    
                if (string.IsNullOrEmpty(categoryName)) 
                throw new FaultException<ServiceException>(ExceptionManager.
                    HandleException("Product ID does not exist in system.")); 
        }catch (Exception ex) 
        { 
            throw new FaultException<ServiceException> 
                (ExceptionManager.HandleException(ex));
        }
    
        return categoryName;
    }
    }
                
  6. Hosting Service

    Host this
    WCF
    service in IIS
    or in Windows service.

  7. Add Client Application

    Now add a console application to the solution. Name it as NorthwindApp.

  8. Add Service Reference

    Add service reference to NorthwindApp by right click on NorthwindApp project and click on Add Service Reference.
    Below the window should appear. Enter the address of the service endpoint which you have added in the service app. config.

    WCF Client Application

    Enter ProductServiceRef for Namespace and click on OK. Service reference is added
    to your client application.

    WCF Client Application

    Check Client application’s App.config, it should have service endpoint and client
    details.

  9. Client Implementation

    Service reference is now available for Northwind. We can call service operations
    and implement error handling using FaultContracts. Add the below code to NorthwindApp
    -> Program.cs file.

                
    class Program
    {
    static void Main(string[] args)
    {
        ShowOperations();
    }
    
    private static  void ShowOperations()
    {
        ConsoleKeyInfo cki;
    
        do
        {
            Console.WriteLine(); 
            Console.WriteLine("Enter Product ID or press Esc to quit : ");
            cki = Console.ReadKey();
            if (!char.IsNumber(cki.KeyChar))
            {
                Console.WriteLine("  Invalid number");
            }
            else
            {
                Int32 number;
                if (Int32.TryParse(cki.KeyChar.ToString(), out number))
                {
                    Console.WriteLine(); 
                    GetProductName(number);
                    GetProductQty(number);
                    GetCategoryName(number);  
                }
                else
                {
                    Console.WriteLine("Unable to parse input");
                }
            }
        } while (cki.Key != ConsoleKey.Escape);
    
        Console.Read(); 
    }
    
    private static void GetProductName(int ProductID)
    {   
        try
        {
            ProductsClient client = new ProductsClient();
            string ProductName = client.GetProductName(ProductID);
            Console.WriteLine(string.Format("Product name {0} for ProductID {1}",
                    ProductName, ProductID));
        }
                catch(FaultException<ServiceException> ex)
        { 
            Console.WriteLine(string.Format("Errors
                occured in service : {0} ", ex.Detail.Message)); 
        }
    }
    
    private static void GetProductQty(int ProductID)
    {   
        try
        {
            ProductsClient client = new ProductsClient();
            int ProductQty = client.GetProductQty(ProductID);
            Console.WriteLine(string.Format("Product qty {0} for Product ID {1}",
                    ProductQty, ProductID));
        }
                 catch(FaultException<ServiceException> ex) 
        { 
            Console.WriteLine(string.Format("Errors
                occured in service : {0} ", ex.Detail.Message)); 
        }
    }
    
    private static void GetCategoryName(int ProductID)
    {
        try
        {
            ProductsClient client = new ProductsClient();
            string CategoryName = client.GetCategoryName(ProductID);
            Console.WriteLine(string.Format("Category name{0} for ProductID {1}",
                    CategoryName,ProductID));
        }
                catch(FaultException<ServiceException> ex) 
        { 
            Console.WriteLine(string.Format("Errors
                occured in service : {0} ", ex.Detail.Message)); 
        }
    }
    }
                

    See the implementation of ServiceException in bold.

While working with code from this article do not forget to mention
appropriate path of data store which can be Products.xml download here.

Понравилась статья? Поделить с друзьями:
  • Error handling response typeerror cannot read properties of undefined reading direction
  • Error handling nestjs
  • Error handling jsf
  • Error handling in node js
  • Error handling file saving did the server never start