locked
Catching a Thrown Exception on the Server RRS feed

  • Question

  • User1663286328 posted


    Hi all,

    Now that I've sorted out my issue with respect to throwing my exception
    when (and only when) it needs to be thrown, I now have the issue of
    catching the exception where I want it to be caught.

    The exception is thrown on the server, but being caught on the client.
    (On top of that, it's coming back as a CommunicationException, and
    not my custom exception handler, but that probably wouldn't happen if
    I could catch the exception on the server to begin with.)

    Can anyone clue me in on how to catch the exception on the server-side?
     ... or perhaps I should ask how to throw it so that the server will
    catch it?

    Thanks!

        class Server_Program
        {
            public static void Main()
            {
                ServiceHost serviceHost = new ServiceHost(typeof(VS_Service));
    
                try
                {
                    serviceHost.Open();
    
                    foreach (Uri baseAddress in serviceHost.BaseAddresses)
                        VSM_Log.mssg.Info
                                ("   *** Service started at {0}", baseAddress);
    
                    VSM_Log.mssg.Info ("");
                    VSM_Log.mssg.Info ("Press <ENTER> to terminate the service");
                    VSM_Log.mssg.Info ("");
                    Console.ReadLine();
    
                    serviceHost.Close();
                }
                catch (not_implemented_exception NI_xcpt)
                {
                    NI_xcpt.add_name ("MAIN <1> (local service)");
                    NI_xcpt.log_error_messages (NI_xcpt);
                }
                catch (CommunicationException e)
                {
                    VSM_Log.mssg.Info (e.Message);
                }
                catch (TimeoutException e)
                {
                    VSM_Log.mssg.Info (e.Message);
                }   
    
                if (serviceHost.State != CommunicationState.Closed)
                {
                    VSM_Log.mssg.Info ("Aborting the service...");
                    serviceHost.Abort();
                }
            }
        }
    



    Tuesday, March 19, 2013 11:36 PM

Answers

  • User1663286328 posted

    Hi sukumarraju,

    I'm sorry that you put in the time and effort to write that response,
    as it does nothing to address my issue. In the example that you've given,
    the exception is caught on the client - not on the server - as I'm in the
    process of doing. I've got plenty of examples for catching exceptions
    on the client, but scarce few for catching them on the server - before
    they are sent on to the client. This is a bit of a surprise, as there could be
    a lot of sensitive information that could make it to the general public
    (or, even worse, a hacker who deliberately trips an exception to get back
    information that could lead to bad things happening).

    In debugging, the more information that a developer/administrator has
    in dealing with an issue, the easier it will be to fit it. The common-sense
    thing to do in that regard is to catch detailed exceptions on the server,
    then send a less-detailed message on to the client.

    The good news is that I seem to have found the key elements in getting
    what I want: the ability to catch exceptions on the server. I found a post
    that has given me the clue that I need to get around the cast exception
    issue that I had before. It seems that, in accessing the collection returned
    in the call to serviceHostBase.ChannelDispatchers, I need to use, as the
    return type, ChannelDispatcherBase (instead of ChannelDispatcher),
    then use an "as" cast to convert it to ChannelDispatcher, then it's
    onward to using it to access the exception handler (unless the cast
    evaluates to null, then it's onward to the next element within the list).

    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(...));
            }
        }
        //Other interface methods omitted for brevity
    }
    
    //http://www.codeproject.com/Articles/26320/WCF-Error-Handling-and-Fault-Conversion

    It looks like I've found the solution to my problem, but if anyone else has
    a better idea, I'd appreciate the input.

    Thanks sukumarraju for the effort, and to everyone else who has been reading

    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Thursday, March 21, 2013 2:35 PM

All replies

  • User-629220960 posted

    Hi ,

    If you have made application in three tier architecture you can handle the exception without rendering on client . Handel the exception in the Model and Controller phaes or in datalayer and BusinessLayer .and create a error log with the help of System.IO namespace.

    Wednesday, March 20, 2013 12:06 AM
  • User1663286328 posted

    Hi Vivek,

    There are only two tiers: client and server.

    I want to throw and catch certain exception(s) on the server,
    and not have it sent to the client.

    BTW: This is self-hosted - no IIS.

    Thanks for the response!

    Wednesday, March 20, 2013 10:36 AM
  • User220959680 posted

    Exceptions are called WCF faults, here is the list of best practices. 

    http://blogs.msdn.com/b/pedram/archive/2008/01/25/wcf-error-handling-and-some-best-practices.aspx

    Wednesday, March 20, 2013 10:52 AM
  • User1663286328 posted

    Hi sukumarraju,

    I've been looking through the referenced Blog:

    ---------------------------------------------------------

    An interesting and useful WCF extensibility point for error handling:
    WCF is a very extensible framework. You can explicitly control the
    behaviour of your application when an exception is thrown.

    You can
    -          Decide to send a fault to the client or not,
    -          Replace an exception with a fault,
    -          Replace a fault with another fault,
    -          Perform logging,
    -          Perform other custom activities

    ---------------------------------------------------------

    "Decide to send a fault to the client or not"

     ... or not.

    I'm still trying to figure out how to do that.

    I've come across a post that mentions the IServiceBehavior interface:
    ---------------------------------------------------------
    http://stackoverflow.com/questions/3308794/wcf-server-side-error-handling-best-practice
    ---------------------------------------------------------

    Have a look at IErrorHandler interface

    It allows an implementer to control the fault message returned
    to the caller and optionally perform custom error processing
    such as logging

    You can implement your service behavior (see IServiceBehavior
    interface) and add your handler to ChannelDispatcher error
    handlers.

    See WCF Exception Handling with IErrorHandler for more details.
    ---------------------------------------------------------
    ---------------------------------------------------------


    I tried this, and, when I attempted to iterate through the
    "ChannelDispatcherCollection", an invalid cast exception was thrown.


                try
                {
                    serviceHost.Open();
    
                    dispatcher_info (serviceHost);
                    //[ EXE1: dispatcher_info <1>]
                .
                .
                .
    
    
            private static void dispatcher_info (ServiceHost p_serviceHost)
            {
                IChannelListener icl = p_serviceHost.ChannelDispatchers[0].Listener;
                ChannelDispatcher dispatcher = new ChannelDispatcher(icl);
    
                VSM_Log.mssg.Info
                            ("servicehost has {0} ChannelDispatchers",
                            p_serviceHost.ChannelDispatchers.Count);
    
                ChannelDispatcherCollection
                dispatchers = p_serviceHost.ChannelDispatchers;
    
                foreach (ChannelDispatcher disp in dispatchers)
                {
                    VSM_Log.mssg.Info ("Binding name: " + disp.BindingName);
                }
            }
    



    System.InvalidCastException was unhandled
      Message=Unable to cast object
      of type 'System.ServiceModel.Discovery.OfflineAnnouncementChannelDispatcher'
      to type 'System.ServiceModel.Dispatcher.ChannelDispatcher'.
      Source=service
      StackTrace: ...
    


    The client is using discovery to find the endpoint.

    Perhaps that has something to do with it?

    THANKS for the response!

    Wednesday, March 20, 2013 1:28 PM
  • User220959680 posted

    https://msevents.microsoft.com/CUI/EventDetail.aspx?culture=en-US&EventID=1032344323

    Just register at above to download/view a detailed video tutorial, all can download all wcf videos . 

    Wednesday, March 20, 2013 2:45 PM
  • User1663286328 posted


    Hi sukumarraju,

    I watched the webcast and it was very informative about sending faults
    to the client - but that is not what I want to know.

    It was only at the end of the webcast that IErrorHandler was mentioned,
    and the means by which to attach it to the service is to be revealed in the
    next webcast - on extensibility.

    I've downloaded the code, and I can see that I'd be spending several hours
    going through it, which is something that I'd rather not do at the present.
    (A lot of it incorporates things that are not relevant to my current situation,
    which is a very simple self-hosted client-server model with duplex operations.)

    All I want to know is how to go about grabbing on to the service thread being
    executed on a ServiceHost, and catching whatever exceptions that might be
    thrown on it before it goes back to the client. Perhaps it's a product of my own
    naivete that it isn't as simple as I thought it should be.

    I'll keep searching for a suitable answer, but I'm still hoping that someone will
    shine a ray of sunshine upon me that will enlighten me to a viable solution ...

    THANKS for the response and the clue on the webcast.

    Wednesday, March 20, 2013 4:57 PM
  • User220959680 posted

    Exceptions can not cross the service boundary.
    WCF automaticaly translates unhandled exceptions into SOAP faults. For security reasons, only a generic message is returned to client.

    In order to include the exception details in faults

    • Enable with ServiceBehavior (shown below) or the ServiceDebug behavior, this is useful for debugging purpose, not recommended in production.
    <configuration>
     <system.serviceModel>
        <behaviors>
    	<behavior name="Default">
              <serviceDebug includeExceptionDetailInFaults="true"/>
        <behaviors>
     </system.serviceModel>
    

    The FaultException class represents an explicity soap fault.

    • Thorw in service operation to return a soap fault.
    • WCF clients can catch FaultException to handle the error
    • It is feasible to throw/catch typed faults.
    Service
    //Service operation
    public void GetProduct(int id)
    {
       try{
            ///
           }
    
        catch(Exception ex)
        {
         throw new FaultException("<Fault reason here>")
         }
    }

    Client side

    Client needs to be prepared for two main exception types.

    1. Communication excepiton - these are various runtime communication exceptions and FaultExceptions thrown by the operations (methods above).
    2. TimeoutException:- send timeout limit exceeded or thrown by underlying transprot channel.
    //Client handling exception
    
    //create an instance service proxy
    productServiceClient client = new productServiceClient();
    
    //Invoke service method
    try
      {
     client.GetProduct(2);
     client.Close();
       }
    //Catch FaultException
    Catch(FaultException fe)
    {
      Console.WriteLine("{0}",fe.GetType());
      Client.Abort();
    }
    
    //Communication exception
    catch(CommunicationException ce)
    {
         Console.WriteLine("{0}",ce.GetType());
         Client.Abort();
    }
    //Timeout exception
    catch(TimeoutException te)
    {
         Console.WriteLine("{0}",te.GetType());
         Client.Abort();
    }
    
    }
    

    Please refer http://msdn.microsoft.com/en-us/library/ms576199.aspx


    Wednesday, March 20, 2013 7:36 PM
  • User1663286328 posted

    Hi sukumarraju,

    I'm sorry that you put in the time and effort to write that response,
    as it does nothing to address my issue. In the example that you've given,
    the exception is caught on the client - not on the server - as I'm in the
    process of doing. I've got plenty of examples for catching exceptions
    on the client, but scarce few for catching them on the server - before
    they are sent on to the client. This is a bit of a surprise, as there could be
    a lot of sensitive information that could make it to the general public
    (or, even worse, a hacker who deliberately trips an exception to get back
    information that could lead to bad things happening).

    In debugging, the more information that a developer/administrator has
    in dealing with an issue, the easier it will be to fit it. The common-sense
    thing to do in that regard is to catch detailed exceptions on the server,
    then send a less-detailed message on to the client.

    The good news is that I seem to have found the key elements in getting
    what I want: the ability to catch exceptions on the server. I found a post
    that has given me the clue that I need to get around the cast exception
    issue that I had before. It seems that, in accessing the collection returned
    in the call to serviceHostBase.ChannelDispatchers, I need to use, as the
    return type, ChannelDispatcherBase (instead of ChannelDispatcher),
    then use an "as" cast to convert it to ChannelDispatcher, then it's
    onward to using it to access the exception handler (unless the cast
    evaluates to null, then it's onward to the next element within the list).

    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(...));
            }
        }
        //Other interface methods omitted for brevity
    }
    
    //http://www.codeproject.com/Articles/26320/WCF-Error-Handling-and-Fault-Conversion

    It looks like I've found the solution to my problem, but if anyone else has
    a better idea, I'd appreciate the input.

    Thanks sukumarraju for the effort, and to everyone else who has been reading

    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Thursday, March 21, 2013 2:35 PM
  • User220959680 posted

    In the example that you've given,
    the exception is caught on the client - not on the server -

    In my previous response exception is caught in Service layer and you are suggested to comment the config behavior in production. Refer the below.

    <div>Service</div>

    //Service operation
    public void GetProduct(int id)
    {
       
    try{
           
    ///
           
    }

       
    catch(Exception ex)
       
    {
         
    throw new FaultException("<Fault reason here>")
         
    }
    }

    Enable with ServiceBehavior (shown below) or the ServiceDebug behavior, this is useful for debugging purpose, not recommended in production. 

    Friday, March 22, 2013 8:00 AM
  • User1663286328 posted


    Hi Sukumarraju,

    What you're suggesting is that I should put the code in every service method
    inside try/catch blocks. I thought of doing that myself, but it I'm not sure that
    it would catch all exceptions thrown.

    Perhaps someone else can comment on this.

    I don't see how this is a better approach than attaching an error handler
    to the channelDispatcher - and this is the approach recommended by
    Bustamante (who has a nice example of it in the extensibility part of her
    example code).

    I've also come accross another approach that you might be interested in.
    It involves the Exception Handling Application Block (a part of Enterprise Library):

    http://msdn.microsoft.com/en-us/library/ff664698%28v=pandp.50%29.aspx

    ltimately, this might be the best way to go, but for now, I'll stick with the
    channelDispatcher error handler.

    Thanks for the responses.

    Saturday, March 23, 2013 12:29 AM
  • User220959680 posted

    wASP

    channelDispatcher

    Thanks for sharing ChannelDispatcher.ErrorHandlers property.

    Note that ErrorHandler class, which is called in ErrorHandlingBehaviorAttribute class is implementing FaultException()as shown below.

    //ExceptionFault in ErrorHandler class
    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);
                }
    
    //creating new instance of ErrorHandler in ErrorHandlingBehaviorAttribute class
    if (channelDispatcher == null)
                    continue;
                channelDispatcher.ErrorHandlers.Add(new ErrorHandler(...));

    what ever the exceptions that are caught using FaultException in the example I provided earlier also does the same in the article/example utilising ChannelDispatcher, the only difference is rather than repeating FaultException in each service method ChannelDispatcher.ErrorHandlers implementation i.e., behavior can be added as Attribute to the service class as below.

    [ErrorHandlingBehavior]
    class MyService : IMyService 

    wASP

    I've also come accross another approach that you might be interested in.
    It involves the Exception Handling Application Block (a part of Enterprise Library):

    Enterprise Lib Exception Handling app block provides consistent error handling across the application using Exception policy. It is required to specify what type of exceptions i.e., FileNotFoundException etc. in the policy and call the policy name in exception handling (Catch) block. It is feasible to specify number of policies and utilise as required. Utilising Application block is simple and all it required is 'using simple configuration tool (more in my articles below).

    Service related exceptions can be wrapped in a Exception policy and utilised in service layer. Client side exceptions can be wrapped in a policy and reused across the application.

    Refer below referred two articles from my blog.

    http://weblogs.asp.net/sukumarraju/archive/2009/10/04/microsoft-enterprise-library-4-1-exception-handling-block.aspx

    http://weblogs.asp.net/sukumarraju/archive/2011/11/07/configuring-wcf-service-to-utilise-enterprise-library-logging-application-to-log-data-to-database.aspx

    wASP

    Perhaps someone else can comment on this.

    Please keep this thread as un-resolved by marking your response as Not an Answer, such a way community member can provide further help.


     

    Sunday, March 24, 2013 7:36 PM