none
WCF low lever error handling RRS feed

  • Question

  • Basically I am looking for a way to handle low level exceptions in WCF – i.e, handle all the exceptions and customize before send it to client.

    I have tried out IErrorHandler, but excpetions like below are not seem to abe able to catch by IErrorHAndler :

    Server stack trace:

       at System.ServiceModel.Security.SecuritySessionClientSettings`1.SecurityRequestSessionChannel.ProcessReply(Message reply, TimeSpan timeout, SecurityProtocolCorrelationState correlationState)

       at System.ServiceModel.Security.SecuritySessionClientSettings`1.SecurityRequestSessionChannel.Request(Message message, TimeSpan timeout)

       at System.ServiceModel.Dispatcher.RequestChannelBinder.Request(Message message, TimeSpan timeout)

       at System.ServiceModel.Channels.ServiceChannel.Call(String action, Boolean oneway, ProxyOperationRuntime operation, Object[] ins, Object[] outs, TimeSpan timeout)

       at System.ServiceModel.Channels.ServiceChannelProxy.InvokeService(IMethodCallMessage methodCall, ProxyOperationRuntime operation)

       at System.ServiceModel.Channels.ServiceChannelProxy.Invoke(IMessage message)

     

    Exception rethrown at [0]:

       at System.Runtime.Remoting.Proxies.RealProxy.HandleReturnMessage(IMessage reqMsg, IMessage retMsg)

       at System.Runtime.Remoting.Proxies.RealProxy.PrivateInvoke(MessageData& msgData, Int32 type)

     

    Please point out how this is achievable in WCF - how this exception can be caught at service side so that i can trace it in the server side and start remediation proactively.

    Monday, June 17, 2019 7:43 AM

All replies

  • How I have seen it handled is that the DTO pattern was used to catch any exception thrown with the exception sent back to the client-side over the WCF boundary  where the exception was logged. If there was no exception, then the DTO continued its path back to the caller on the client-side.

    Here is a crude example of what I am talking about where SoC was applied to the WCF service project that had reference to a Repository pattern classlib project that had reference to the low level mapping with the database in the Data Access Layer using the Entity Framework and CRUD operations. No try/catch was in the Repository object or the DAO (Data Access Object) pattern  used in the DAL 

    https://en.wikipedia.org/wiki/Separation_of_concerns

    https://en.wikipedia.org/wiki/Data_transfer_object

    https://www.codeproject.com/Articles/1050468/Data-Transfer-Object-Design-Pattern-in-Csharp

    the ServiceLayer client-side...

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using Entities;
    
    namespace ServiceLayer
    {
        public class ServiceA : IServiceA
        {
            public List<DTOStudent> GetStudents()
            {
                var dtos = new List<DTOStudent>();
    
                var client = new WCFServiceReference1.Service1Client();
    
                dtos = client.GetStudents().ToList();
                 
                if (dtos[0].DtoResponse.Message != null)
                {
                    throw new Exception(dtos[0].DtoResponse.Message + " " + dtos[0].DtoResponse.InnerException
                        + " " + dtos[0].DtoResponse.StackTrace);
                }
    
                return dtos;
            }
    
            public DTOStudent GetStudentById(Int32 id)
            {
                var client = new WCFServiceReference1.Service1Client();
    
               var dto = client.GetStudentById(id);
    
                if (dto.DtoResponse.Message != null)
                {
                    throw new Exception(dto.DtoResponse.Message + " " + dto.DtoResponse.InnerException
                        + " " + dto.DtoResponse.StackTrace);
                }
    
                return dto;
            }
            public void CreateStudent(DTOStudent dto)
            {
                var client = new WCFServiceReference1.Service1Client();
    
                var dtor = client.CreateStudent(dto);
    
                if (dtor != null)
                {
                    throw new Exception(dtor.DtoResponse.Message + " " + dtor.DtoResponse.InnerException
                        + " " + dtor.DtoResponse.StackTrace);
                }
            }
            public void UpdateStudent(DTOStudent dto)
            {
                var client = new WCFServiceReference1.Service1Client();
    
                var dtor = client.UpdateStudent(dto);
    
                if (dtor != null)
                {
                    throw new Exception(dtor.DtoResponse.Message + " " + dtor.DtoResponse.InnerException
                        + " " + dtor.DtoResponse.StackTrace);
                }
            }
            public void DeleteStudent(Int32 id)
            {
                var client = new WCFServiceReference1.Service1Client();
    
                var dtor = client.DeleteStudent(id);
    
                if (dtor != null)
                {
                    throw new Exception(dtor.DtoResponse.Message + " " + dtor.DtoResponse.InnerException
                        + " " + dtor.DtoResponse.StackTrace);
                }
            }
        }
    }
    

    Sevice-side

    using System;
    using System.Collections.Generic;
    using Entities;
    using Repository;
    
    namespace WcfService
    {
        public class Service1 : IService1
        {
            private IStudentRepo _studentRepo;
            private IEnrollmentRepo _enrollmentRepo;
            private DTOStudent dto;
            public Service1(IStudentRepo studentRepo, IEnrollmentRepo enrollmentRepo)
            {
                _studentRepo = studentRepo;
                _enrollmentRepo = enrollmentRepo;
    
            }
            public DTOStudent GetStudentById(Int32 id)
            {
                try
                {
                    return _studentRepo.GetStudentById(id);
                }
                catch (Exception e)
                {
                    dto = new DTOStudent();
    
                    dto.DtoResponse.Message = e.Message;
                    if (e.InnerException != null) dto.DtoResponse.InnerException = e.InnerException.Message;
                    dto.DtoResponse.StackTrace = e.StackTrace;
    
                    return dto;
                }
            }
            public List<DTOStudent> GetStudents()
            {
                try
                {
                    return _studentRepo.GetStudents();
                }
                catch (Exception e)
                {
                    var dtos = new List<DTOStudent>();
                    dto = new DTOStudent();
    
                    dto.DtoResponse.Message = e.Message;
                    if (e.InnerException != null) dto.DtoResponse.InnerException = e.InnerException.Message;
                    dto.DtoResponse.StackTrace = e.StackTrace;
         
                    dtos.Add(dto);
                    return dtos;
                } 
            }
    
            public DTOStudent CreateStudent(DTOStudent dto)
            {
                try
                {
                    _studentRepo.CreateStudent(dto);
                    return null;
                }
                catch (Exception e)
                {
                    dto = new DTOStudent();
    
                    dto.DtoResponse.Message = e.Message;
                    if (e.InnerException != null) dto.DtoResponse.InnerException = e.InnerException.Message;
                    dto.DtoResponse.StackTrace = e.StackTrace;
    
                    return dto;
                }
            }
            public DTOStudent UpdateStudent(DTOStudent dto)
            {
                try
                {
                    _studentRepo.UpdateStudent(dto);
                    return null;
                }
                catch (Exception e)
                {
                    dto = new DTOStudent();
    
                    dto.DtoResponse.Message = e.Message;
                    if (e.InnerException != null) dto.DtoResponse.InnerException = e.InnerException.Message;
                    dto.DtoResponse.StackTrace = e.StackTrace;
    
                    return dto;
                }
            }
            public DTOStudent DeleteStudent(Int32 id)
            {
                try
                {
                    _studentRepo.DeleteStudent(id);
                    return null;
                }
                catch (Exception e)
                {
                    dto.DtoResponse.Message = e.Message;
                    if (e.InnerException != null) dto.DtoResponse.InnerException = e.InnerException.Message;
                    dto.DtoResponse.StackTrace = e.StackTrace;
    
                    return dto;
                }
            }
         }
    }
    

    using System;
    using System.Collections.Generic;
    using System.Runtime.Serialization;
    
    namespace Entities
    {
       [DataContract] 
        public class DTOStudent
        {
            
            private DTOResponse dtor = new DTOResponse();
    
            [DataMember]
            public Int32 StudentID { get; set; }
    
            [DataMember]
            public string LastName { get; set; }
    
            [DataMember]
            public string FirstName { get; set; }
    
            [DataMember]
            public DateTime? EnrollmentDate { get; set; }
    
            [DataMember]
            public virtual ICollection<DTOEnrollandCourse> EnrollsandCourses { get; set; }
    
            [DataMember]
            public DTOResponse DtoResponse
            {
                get { return dtor; }
                set { dtor = value; }
            } 
        }
    }
    

    namespace Entities
    {
        public class DTOResponse
        {
            public string Message { get; set; }
            public string StackTrace { get; set; }
            public string InnerException { get; set; }
        }
    }
    


      
    Tuesday, June 18, 2019 7:38 AM
  • Hi,

    Most of the cases the errors could be captured by the client or the server.  Somehow, some low-level errors could not be caught by IErrorhandler interface, this has been discussed online for a long time. Please refer to the below link.
    https://social.msdn.microsoft.com/Forums/vstudio/en-US/21b77052-2b6e-439c-80b6-83607393edb2/how-to-handle-low-level-wcf-errors?forum=wcf
    Besides, I have ever written a sample on using IErrorHandler interface, wish it is useful to you.
    https://stackoverflow.com/questions/51941487/wcf-exception-handling-approcah/52031944#52031944
    Best Regards
    Abraham


    Tuesday, June 18, 2019 8:16 AM
    Moderator
  • Thanks for the response.

    But the problem i am trying to tackle is :

    How to hook in to the wcf pipeline to catch these kind of exceptions at the service side.

    Like the service behavior extensions , can we hook in to the wcf  "service transport channel" or so and customize the exceptions before sending it to client.

    Tuesday, June 18, 2019 9:14 AM
  • Thanks for the response.

    But the problem i am trying to tackle is :

    How to hook in to the wcf pipeline to catch these kind of exceptions at the service side.

    Like the service behavior extensions , can we hook in to the wcf  "service transport channel" or so and customize the exceptions before sending it to client.

    I have IErrorHandler implemented and hooked to service behavior, but exceptions happening at System.ServiceModel.Security level or Syste..ServiceModel.EndpointNotFoundExceptions are not captured by the ProvideFault of IErrorHandler.

    Tuesday, June 18, 2019 9:18 AM
  • Thanks for the response.

    But the problem i am trying to tackle is :

    How to hook in to the wcf pipeline to catch these kind of exceptions at the service side.

    Like the service behavior extensions , can we hook in to the wcf  "service transport channel" or so and customize the exceptions before sending it to client.


    All I can tell you is that a MS conversion team from MS I worked with in using WCF for a major MS client used the approach I am talking about of just catching the exception on the WCF service side whatever the exception was about and sending the exception back in the response object, using the  request/response pattern.
    Tuesday, June 18, 2019 9:56 AM
  • @DA924x

    I would consider the repository where the the exception happens in the first answer is happening within the application after the request reached the service  - i.e application exception only.

    Where as the case I want to handle is that the request is not even reaching the actual service contract, even before that at the service boundary for eg:- due to security violations exceptions is being thrown from the WCF Service Transport Channel/Service Channel/Dispatcher.


    • Edited by fozzpaz Tuesday, June 18, 2019 2:05 PM
    Tuesday, June 18, 2019 2:04 PM
  • @DA924x

    I would consider the repository where the the exception happens in the first answer is happening within the application after the request reached the service  - i.e application exception only.

    Where as the case I want to handle is that the request is not even reaching the actual service contract, even before that at the service boundary for eg:- due to security violations exceptions is being thrown from the WCF Service Transport Channel/Service Channel/Dispatcher.


    Maybe,  you need Global Exception Handling on WCF service-side to catch all unhandled exceptions.

    https://stackify.com/csharp-catch-all-exceptions/

    Tuesday, June 18, 2019 3:47 PM