Ask a questionAsk a question
 

AnswerStrange WCF behavior

  • Sunday, November 08, 2009 12:52 AMGarF1eld Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     
    Hello,
    I have a simple Wcf service, which sends a message to clients every 700 seconds. Client also has an ability to recieve a message from the server
    The Server:

    ServiceContract
       [ServiceContract(CallbackContract = typeof(IClientCallback))]
        public interface ISampleService
        {
            [OperationContract(IsOneWay = true)]
            void RegisterClient();
    
            [OperationContract(IsOneWay = true)]
            void UnregisterClient();
    
            [OperationContract]
            String RecieveString();
        }
    Callback contract:
        [ServiceContract]
        public interface IClientCallback
        {
            [OperationContract(IsOneWay = true)]
            void NewMessage(String message);
        }
    Service implementation
        [ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)]
        public class SampleService : ISampleService
        {
            private List<IClientCallback> _Callbacks = new List<IClientCallback>();
            private object lockCallbacks = new object();
    
            private Timer _TimerCallbacks;
    
            public SampleService()
            {
                _TimerCallbacks = new Timer(OnTimer, null, 0, 700);
            }
    
            // timer callback
            public void OnTimer(object state)
            {
                lock (lockCallbacks)
                {
                    for (int i = 0; i < _Callbacks.Count; i++)
                        try
                        {
                            _Callbacks[i].NewMessage(String.Format("Client callback", DateTime.Now));
                        }
                        catch (CommunicationException)
                        {
                            // channel faulted
                            _Callbacks.RemoveAt(i);
                            i--;
                        }
                }
            }
    
            #region ISampleService Members
    
            public void RegisterClient()
            {
                OperationContext context = OperationContext.Current;
                IClientCallback c = context.GetCallbackChannel<IClientCallback>();
                lock (lockCallbacks)
                    _Callbacks.Add(c);
            }
    
            public void UnregisterClient()
            {
                OperationContext context = OperationContext.Current;
                IClientCallback c = context.GetCallbackChannel<IClientCallback>();
                lock (lockCallbacks)
                    _Callbacks.Remove(c);
            }
    
            public string RecieveString()
            {
                return "Client request";
            }
    
            #endregion
        }
    

    This is the part where the server is created
                SampleService instance = new SampleService();
                ServiceHost host = new ServiceHost(instance);
    
                NetTcpBinding binding = new NetTcpBinding(SecurityMode.None);
                binding.MaxReceivedMessageSize = Int32.MaxValue;
    
                host.AddServiceEndpoint(typeof(ISampleService),
                    binding,
                    new Uri("net.tcp://localhost:888/SampleService"));
    
                // set all throttlings to maximum to ensure the problem is not here
                ServiceThrottlingBehavior bhvrThrottling = new ServiceThrottlingBehavior();
                bhvrThrottling.MaxConcurrentCalls = Int32.MaxValue;
                bhvrThrottling.MaxConcurrentInstances = Int32.MaxValue;
                bhvrThrottling.MaxConcurrentSessions = Int32.MaxValue;
    
                host.Description.Behaviors.Add(bhvrThrottling);
    
                // mex
                host.Description.Behaviors.Add(new ServiceMetadataBehavior());
                Binding mexBinding = MetadataExchangeBindings.CreateMexTcpBinding();
                host.AddServiceEndpoint(typeof(IMetadataExchange),
                    mexBinding,
                    new Uri("net.tcp://localhost:888/SampleService/mex"));
    
                host.Open();

    The Client:

    There are proxy was generated by Visual Studio and implementation of the callback
        class ServiceCallback : ISampleServiceCallback
        {
            #region ISampleServiceCallback Members
    
            public void NewMessage(string message)
            {
                Debug.WriteLine(message);
            }
    
            #endregion
        }
    

    But here is the most fun part. I've got a code, that registers for server's messages and requests it manually every 700 ms.
                ServiceCallback service = new ServiceCallback();
                SampleServiceClient client = new SampleServiceClient(new InstanceContext(service));
                 
                client.RegisterClient();
                Debug.WriteLine("Connected...");
    
                for (;;)
                {
                    Debug.WriteLine(client.RecieveString());
                    Thread.Sleep(700);
                }
    
    1) If i run this code in Console app it works fine
    2)  If i run this code in WinForm or WPF app it fails with TimeoutException  on client.RecieveString()

    How can i solve this???

    The full code you can see here http://depositfiles.com/files/8wf6ywkah 
    PS The Debug class is using

Answers

  • Monday, November 09, 2009 2:14 PMGarF1eld Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     Answer
    the solution was found on another blog - codehelper.ru:

    All we have to do is to change ConcurrencyMode to Reetrant in ServiceBegavior for our SampleService and to set UseSynchronizationContext to false in CallbackBehavior for ServiceCallback

    It works fine for me
    • Marked As Answer byGarF1eld Monday, November 09, 2009 2:14 PM
    •  

All Replies

  • Sunday, November 08, 2009 11:22 AMGarF1eld Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     Has Code
    I still keep trying to manage this and i've found that if this code is run in a separate thread, it just works.
    Is this the way as it should be??? Is this because forms interface runs in a single thread?

                ThreadPool.QueueUserWorkItem((s) =>
                    {
                        ServiceCallback service = new ServiceCallback();
                        SampleServiceClient client = new SampleServiceClient(new InstanceContext(service));
                        client.RegisterClient();
                        Debug.WriteLine("Connected...");
    
                        for (; ; )
                        {
                            Debug.WriteLine(client.RecieveString());
                            Thread.Sleep(700);
                        }
                    });
    
    


    Cmon, I extremely need a solution. Any advices how to avoid this?
  • Monday, November 09, 2009 11:24 AMGarF1eld Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     
    It seems to be a bug, doesnt it?

    Is there reason to keep the service logic in separate thread??? 

    Can somebody help me? msft?
  • Monday, November 09, 2009 2:14 PMGarF1eld Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     Answer
    the solution was found on another blog - codehelper.ru:

    All we have to do is to change ConcurrencyMode to Reetrant in ServiceBegavior for our SampleService and to set UseSynchronizationContext to false in CallbackBehavior for ServiceCallback

    It works fine for me
    • Marked As Answer byGarF1eld Monday, November 09, 2009 2:14 PM
    •