2

Trying to test the reliability of my wcf services. I am calling a wcf service within a loop from the client side. The wcf rest service (webhttpbinding) does some data processing and inserts records into a database. The entire operation is done within a transaction.

I find that out of about 60 messages (60 times the service being called from inside a loop) only 40 are going through to the db if I set my InstanceContextMode to PerCall. There are no errors no exceptions. The messages are just being dropped.

If I set the InstanceContextMode to Single then I see all messages getting to the db. Is the InstanceContextMode.Percall being lossy the expected behavior? Also, I do not have concurrency set. Any clarifications would be greatly helpful. Added the code. Using MySQL as the db...

EDIT My bad - I just noticed that I get an exception on the server side - {"Deadlock found when trying to get lock; try restarting transaction"}

This is because there is another transaction invoked on the same records while a transaction is under progress. Fixing it by restarting the transaction if it fails once.

The service

    [WebInvoke(UriTemplate = "employee", Method = "POST")]
    public long AddNewEmployee(EmployeeEntity newEmployee)
    {
        EmployeeRepository eRep = new EmployeeRepository();
        return eRep.AddNewEmployee(newEventEntity);                     
    }

The repository class constructor initializes the object context

    public EmployeeRepository()
    {
        bd = new EmployeeEntity();
    }

Code - The service call

    //bd is the object context 
    //there are two tables 
    internal long AddNewEmployee(EmployeeEntity newEmployee)
    {
        bool tSuccess = false;
        using (TransactionScope transaction = new TransactionScope())
        {
            try
            {
                //get existing employees
                var existingEmployees = from employee
                                        in bd.employees select employee;


                List<employee> returnedEmployees = new List<employee>();                    

                //Do some processing 
                returnedEmployees = DoSomeprocessing(existingEmployees);

                //Insert returned employees as updates
                foreach (employee e in returnedEmployees)
                {
                    bd.employees.AddObject(e);
                }

                bd.SaveChanges();
                returnedEmployees.Clear();

                //add to second table 
                bd.otherdetails.AddObject(newEmployee);
                bd.SaveChanges();


                //Transaction Complete                        
                transaction.Complete();
                tSuccess = true;

            }
            catch (Exception e)
            {
                //return something meaningful 
                return -1;                    
            }
        }

        if (tSuccess)
        {
            //End Transaction
            bd.AcceptAllChanges();
            return 200;
        }            
        else
        {
           return -1;
        }

    }

The client side just calls the service in a loop

user275157
  • 1,332
  • 4
  • 23
  • 45
  • 1
    When you say "There are no errors no exceptions", what do you mean exactly? The client is not seeing any errors? The WCF Exception handler is not firing? There is no exception within the service method itself? – Brook Apr 01 '11 at 19:21
  • The client is not seeing any errors. The server method throws no exception as well. Some calls to the service are just dropped. When I use instancecontext single mode however everything works fine.. – user275157 Apr 01 '11 at 19:30

1 Answers1

0

I highly suggest adding global exception handling for any WCF. It has helped me save many hours of debugging and will catch any unhandled exceptions. It's a little bit more involved than global.ascx in ASP.NET

Step 1 - Implement IErroHander and IServiceBehavior

Notice inside HandleError I'm using Enterprise Library to handle the exception. You can use your custom implementation here as well.

 public class ErrorHandler : IErrorHandler, IServiceBehavior
        {        
            public bool HandleError(Exception error)
            {
                // Returning true indicates you performed your behavior.
                return true;
            }


            public void ProvideFault(Exception error, MessageVersion version, ref Message fault)
            {            
                // Log Exception

                ExceptionPolicy.HandleException(error, "ExceptionPolicy");

                // Shield the unknown exception
                FaultException faultException = new FaultException(
                    "Server error encountered. All details have been logged.");
                MessageFault messageFault = faultException.CreateMessageFault();

                fault = Message.CreateMessage(version, messageFault, faultException.Action);
            }

            private IErrorHandler errorHandler = null;

            public ErrorHandler()
            {

            }

            public ErrorHandler(IErrorHandler errorHandler)
            {
                this.errorHandler = errorHandler;
            }

            public void ApplyDispatchBehavior(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
            {
                foreach (ChannelDispatcherBase cdb in serviceHostBase.ChannelDispatchers)
                {
                    ChannelDispatcher cd = cdb as ChannelDispatcher;

                    if (cd != null)
                    {
                        cd.ErrorHandlers.Add(new ErrorHandler());
                    }
                }
            }

            public void AddBindingParameters(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase, Collection<ServiceEndpoint> endpoints, BindingParameterCollection bindingParameters)
            {
                foreach (ChannelDispatcherBase cdb in serviceHostBase.ChannelDispatchers)
                {
                    ChannelDispatcher cd = cdb as ChannelDispatcher;

                    if (cd != null)
                    {
                        cd.ErrorHandlers.Add(new ErrorHandler());
                    }
                }
            }

            public void Validate(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
            {

            }
        }

    }

Step 2 - Create Error Element

public class ErrorHandlerElement : BehaviorExtensionElement
    {
        protected override object CreateBehavior()
        {
            return new ErrorHandler();
        }

        public override Type BehaviorType
        {
            get
            {
                return typeof(ErrorHandler);
            }
        }
    }

Step 3 - Add Element to web.config

<serviceBehaviors>
        <behavior>                              
          <ErrorHandler />
        </behavior>
      </serviceBehaviors>
Alex
  • 170
  • 1
  • 6