.NET Framework Developer Center > .NET Development Forums > Windows Communication Foundation > Server throws exception and client proxy is faulted. How to change this behaviour of client?
Ask a questionAsk a question
 

AnswerServer throws exception and client proxy is faulted. How to change this behaviour of client?

  • Wednesday, October 28, 2009 1:56 PMshaviraghu Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     
    Hi all,
     I am new to WCF. And am developing a chat application using netTcpBinding, since i use it only in LAN. To make my client and server more responsive i have used asynchronous calls. Everything goes fine until a client crashes and the server is unaware of it. So when one of the client tries to send  a message to the crashed client the server tries to send it using a callback untill it times out which is 1 minute and handles the exception.Mean while the client connection gets faulted. I want to make client totally decoupled from server exceptions.

    Please help me.

    Thank u

    Raghu 

Answers

  • Thursday, November 05, 2009 10:40 AMWaldemar Huber Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     Answer
    Hi Raghu,

    the problem is the ReliableSession. When you use it then you can kill your host but your clients would not be notified instantly because the ReliableSessionBindingElement would try to reestablish the connection or something like that. After some time the ReliableSession would give up and delegate the error to upper channels/wcf.

    I tried your project without the reliable session and it worked.

    Btw, your clients needs 100% of the CPU. Check your while loops ;) Without them your clients behaved normal.

    I hope I could help you.
    Waldemar Huber
    • Marked As Answer byshaviraghu Thursday, November 05, 2009 12:38 PM
    •  

All Replies

  • Wednesday, October 28, 2009 2:15 PMWaldemar Huber Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     
    Hi Raqhu,

    you can change the SendTimeout and ReceiveTimeout on your client binding to allow longer timeouts.

    But normally in a chat programm where you don't have to transmit large data you don't need the above hint. As you are using NetTcpBinding your service and client knows all the time about their partner connections, it's a TCP behavior and doesn't come from WCF. You have to show us how you are creating the host and instantiating the clients. Do you use AddServiceReference for the client oder just instantiating directly through code with ChannelFactry or DuplexChannelFactory? Just show it to us and we will show you how you can arrive the events provided by WCF on closing and faulting clients and services.

    Waldemar
  • Thursday, October 29, 2009 5:08 AMshaviraghu Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     
    Hi Waldemar,

    I am using AddServiceReference at client to create a proxy. The Service times out trying to send message to crashed client and the message sender client receives communication exception and proxy is faulted.


    Waiting for ur reply

    Raghu
  • Thursday, October 29, 2009 7:39 AMWaldemar Huber Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     
    Hi Raghu,

    since you are using the generated proxy you have nothing to cast. Just use the ChannelFactory and InnerChannel property and sign on the closed and faulted event. At the moment I don't know which of two properties, but I would take InnerChannel first ;)

    YourProxy.InnerChannel.Closed += new EventHandler(OnMyServiceClosed...);
    YourProxy.InnerChannel.Faulted += new EventHandler(OnMyServiceFaulted...);

    I don't know how you instantiate your service instances by a client connection, but everytime a client call the service you can get the operation context. I think you use it already because of the callback. Just use the channel property of this operation context and register the closed and faulted event only on the first call from a client. You have to register once per client.

    OperationContext.Current.Channel.Closed += ...
    OperationContext.Current.Channel.Faulted += ...

    When your event is called you have to remove your client from the list or something you use to store the connections and perhaps inform the other clients of the missing client. When one of your alive clients try to send a message you have ofcourse to check if that desired client is available or not. Additionally it is useful when you do not just call the desired partner client from your srevice but use try-catch, because it could happen that the closed or faulted event hasn't been yet risen because of strange network errors and internal tcp timeouts.

    I hope I could help.
    Waldemar
  • Thursday, October 29, 2009 11:25 AMshaviraghu Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     
    Hi Waldemar,

    This doesnt improve my app condition.The root problem is the service automatically faults the calling proxy whenever an exception occurs. Like here the service timesout calling a crashed client and receives timeout exception and i dont know how but it automatically faults the calling client and a communicationexception is received at calling client.

    I hope my explaination is clear.

    Thank u.

    waiting for ur reply.

    Raghu.
  • Thursday, October 29, 2009 12:24 PMtechnocrat_aspire Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     
    Hi,

    Just to confirm, are you sending back faults from the service to the client. If you are sending faultcontracts back, the client ideally should fail gracefully instead of a crash.
  • Thursday, October 29, 2009 12:49 PMWaldemar Huber Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     
    Did you try to change the SendTimeout and ReceiveTimeout on your client? Your first calling client has to wait until the service has informed the other client. Your service has to wait his own SendTimeout to the crashed client, but this SendTimeout is the same like of your first client. So when the crashed client timeout has arrived, the timeout of the first client has also arrived.

    Set the Send- and ReceiveTimeout of the clients to a higher value. Test it.

    If it is not the problem then perhaps you don't catch the exception inside the service! If an exception is thrown inside the service then this service will automatically closed. When you call your crashed client you have to use try-catch and inform your first client if the call to the crashed client fails. Don't throw any exceptions at your service ;)
  • Thursday, October 29, 2009 1:03 PMshaviraghu Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     
    hi techno,

    I am not talking of the calling client crashing after service throws an exception. My case is,

    1.Using netTcpBinding.
    2.ReliableSession enabled.
    3.Operation Contracts are oneway.
    4.Using asynchronous calls.
    5.Using a proxy at client side to call service.

    So with these settings i havedeveloped a chat application. I have a connect and disconnect operation contracts. 

    The problem is when a client crashes without disconnecting from service and so its status is not known at service and other clients.so now when a client tries to send a message to this crashed client through service operation contract the service tries for 1minute(which is my setting) and gets a timeout exception and simultaneously the calling client proxy is faulted and communicationexception is thrown . I dont want this behaviour at client side.I dont want my client be faulted because i communicated with a crashed client.Instead the calling client should be informed that the client to which i am trying to communicate is no more available online. 

    I hope i am clear now.

    Raghu
  • Thursday, October 29, 2009 1:47 PMWill.Rogers Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     
    The CommunicationException's and the ChannelFaulted events are WCF's way of letting you know the other side isn't there. At the time you receive these notification, the underlying Channel is in an unrecoverable state. You have to gracefully handle these events and exceptions so that your application behaves in a logical way for the end user.
  • Thursday, October 29, 2009 2:04 PMshaviraghu Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     
    Hi will,

    Ya will i agree with you but i am totally unaware of how to handle these at service side and not faulting client.

    I dont know how to stop service from defaulting client proxy. Even though i handle all the exceptions at service once exception is caught it also faults innerduplex channel.

    plz help me.

    Raghu.
  • Thursday, October 29, 2009 2:39 PMWaldemar Huber Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     
    Hi Raghu,

    as I understand you it is not a big problem to solve this.

    Example:

    You set on your clients the SendTimeout to 2 minutes.
    Client A and B are connected to the service, which has 1 minute SendTimeout.

    So, if client B crashes, you will be informed over events if you want it (with NetTcp it's not a problem). When now client A calls client B over your service, your service should know that client B is not in the clientslist and response to client A with something like "not connected" or bool as return value.
    But, even if you don't remove client B when he crashes at your service, it is as follows: Client A calls your service to communicate with client B, your service tries to inform client B and waits 1 minute until timeout and catches the exception after the timeout. Since client A has 2 minutes timeout, he is still waiting for a reply and you can answer to client A from the catch block with something like bool that your service couldn't connect to client B.

    If you catch the exception of the crashed client on your service and don't throw another exceptions then it's not the service who is faulting the client A! It's the proxy object itself at your client A which has a timeout of 1 minute.

    Give us your example project if it is possible :)

    Notice: If you use the generated proxy object, then your client doesn't call asynchronously the service! It simulates the asynchronous methods only at your client level. Your service still has only synchronous versions. It's the same like you would call the synchronous versions with a custom delegate where you can call every method with Begin() and End().
  • Friday, October 30, 2009 5:54 AMshaviraghu Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     
    Hi waldemar,
     
    First of all i want to thank u for being patient with me and replying me.

    Ya about the problem the faulting of channel doesnt wait for receive timeout or send timeout once the service gets exception the channel is automatically faulted.As will said i think we cant do much about this default behaviour of wcf.But how we handle such situation is important. i think i want to solve it by using events as u mentioned it.Can u plz tell me how to do it.


    Raghu
  • Friday, October 30, 2009 8:39 AMWaldemar Huber Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     
    Hi Raghu,

    please provide us with some example code or explain us your architecture. You chat with other chat partners centrally over your service, am I right? When client A sends a message to client B then this message goes first through your service and when client B replies then this message goes also through service?

    If it so like I described below, then you should be able to catch the exception on your service. When client A sends a message through service and the service tries to communicate to client B then put this code in a try-catch block an when there is an exception then just response to client A with a custom message where you can say that the desired partner is not available.

    Like here:

    [OperationContract]
    bool SendMessageToPartner(string senderID, string receiverID, string message);

    and then in your service:

    public bool SendMessageToPartner(string senderID, string receiverID, string message)
    {
         try
         {
               clients[receiverID].SendMessage(senderID, message);
         }
         catch
         {
               clients.Remove(...someway to reference the client...);
               return false;
         }

         return true;
    }

    Waldemar Huber
  • Friday, October 30, 2009 9:51 AMshaviraghu Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     
    Hi Waldemar,

    It is exactly the way u described it.

    Here is the client and service contract.

    [ServiceContract(CallbackContract = typeof(IChatCallback), SessionMode = SessionMode.Required)]
        public interface IChat
        {
            [OperationContract(IsInitiating = true)]
            bool Connect(Client client);

            [OperationContract(IsOneWay = true)]
            void Say(Message msg);

            [OperationContract(IsOneWay = true)]
            void Whisper(Message msg, Client receiver);

            [OperationContract(IsOneWay = true)]
            void ReportDownloadProgressToSender(ReportDownloadProgressMessage msg,Client receiver);

            [OperationContract(IsOneWay = true)]
            void IsWriting(Client client);

            [OperationContract(IsOneWay = false)]
            bool SendFile(FileMessage fileMsg, Client receiver);

            [OperationContract(IsOneWay = true, IsTerminating = true)]
            void Disconnect(Client client);
        }

        public interface IChatCallback
        {
            [OperationContract(IsOneWay = true)]
            void RefreshClients(List<Client> clients);

            [OperationContract(IsOneWay = true)]
            void Receive(Message msg);

            [OperationContract(IsOneWay = true)]
            void ReceiveWhisper(Message msg, Client receiver);

            [OperationContract(IsOneWay = true)]
            void UpdateDownloadProgress(ReportDownloadProgressMessage msg);

            [OperationContract(IsOneWay = true)]
            void IsWritingCallback(Client client);

            [OperationContract(IsOneWay = true)]
            void ReceiverFile(FileMessage fileMsg, Client receiver);

            [OperationContract(IsOneWay = true)]
            void UserJoin(Client client);

            [OperationContract(IsOneWay = true)]
            void UserLeave(Client client);
        }


    Now client sends a message to crashed client through server using proxy,

    private void Send()
            {
                if (proxy != null && chatTxtBoxType.Text != "")
                {
                    if (proxy.State == CommunicationState.Faulted)
                    {
                        HandleProxy();
                    }
                    else
                    {
                        //Create message, assign its properties
                        SVC.Message msg = new WPFClient.SVC.Message();
                        msg.Sender = this.localClient.Name;
                        msg.Content = chatTxtBoxType.Text.ToString();
                        string rcvr = ((Wpf.Controls.TabItem)tabControl1.SelectedItem).Header.ToString();
                        if ( rcvr!= "Conference")
                        {
                            try
                            {
                                proxy.WhisperAsync(msg, this.receiver);
                            }
                            catch (FaultException ex)
                            {
                                MessageBox.Show("FaultException :" + ex.Message);

                            }
                            catch (CommunicationException ex)
                            {
                                MessageBox.Show("CommunicationException :" + ex.Message);
                            }
                            catch (TimeoutException ex)
                            {
                                MessageBox.Show("TimeoutException :" + ex.Message);
                            }
                            catch (Exception ex)
                            {
                                MessageBox.Show("TimeoutException :" + ex.Message);
                            }
                            //proxy.Whisper(msg, this.receiver);
                            chatTxtBoxType.Text = "";
                            chatTxtBoxType.Focus();
                        }
                        else
                        {
                            proxy.SayAsync(msg);
                            chatTxtBoxType.Text = "";
                            chatTxtBoxType.Focus();
                        }
                       
                    }
                }
            }

    Now at service side

    public void Whisper(Message msg, Client receiver)
            {
                foreach (Client rec in chatters.Keys)
                {
                    if (rec.Name == receiver.Name)
                    {
                        ChatEventHandler handler = chatters[rec];
                        ChatEventArgs e = new ChatEventArgs();
                        e.receiveWhisper = true;
                        e.person = rec;
                        e.message = msg;
                        e.receiver = rec;
                        handler.BeginInvoke(this, e, new AsyncCallback(EndAsync), null);
                        
                        
                        //IChatCallback callback = clients[rec];
                        //callback.ReceiveWhisper(msg, rec);

                        foreach (Client sender in clients.Keys)
                        {
                            if (sender.Name == msg.Sender)
                            {
                                ChatEventHandler handler1 = chatters[sender];
                                ChatEventArgs e1 = new ChatEventArgs();
                                e1.receiveWhisper = true;
                                e1.person = sender;
                                e1.receiver = rec;
                                e1.message = msg;
                                handler1.BeginInvoke(this, e1, new AsyncCallback(EndAsync), null);
                               
                                return;
                            }
                        }
                    }
                }
            }

    and ChatEventHandler

    the service maintains a key value collection of client object and its callback

    IChatCallback callback = clients[e.receiver];
    try
                { 

    callback.ReceiveWhisper(e.message, e.receiver);
                 }
           catch (FaultException ex)
                {
                    MessageBox.Show("FaultException"+c.Name + ex.Message);
                    Disconnect(e.receiver);
                }
                catch (CommunicationException ex)
                {
                    MessageBox.Show("CommunicationException"+c.Name + ex.Message);
                    Disconnect(c);
                }
                catch (TimeoutException ex)
                {
                    MessageBox.Show("TimeoutException"+c.Name + ex.Message);
                    Disconnect(e.receiver);
                }
                catch (Exception ex)
                {
                    MessageBox.Show("Exception" +c.Name+ ex.Message);
                    Disconnect(e.receiver);
                }


    so this is it .


    Raghu
  • Friday, October 30, 2009 10:20 AMWaldemar Huber Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     
    What is ChatEventHandler, is BeginInvoke a method written by you or given through .NET? And what do you do in EndAsync? And, when you try to call the callback, which exception is handeled? And what do you do in Disconnect(e.receiver)?

    Waldemar
  • Friday, October 30, 2009 11:54 AMshaviraghu Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     
    ChatEventHandler is written by me. BeginInvoke used is given by .NET  

    public delegate void ChatEventHandler(object sender, ChatEventArgs e);

    and this is the method being called

    private void MyEventHandler(object sender, ChatEventArgs e)
            {

                Client c = e.person;
                IChatCallback callback = clients[c];
                
                try
                {

                    if (e.receive)
                    {
                        callback.Receive(e.message);
                    }
                    if (e.receiveWhisper)
                    {
                        callback.ReceiveWhisper(e.message, e.receiver);
                    }
                    if (e.receiveFile)
                    {
                        callback.ReceiverFile(e.fMessage, e.receiver);
                    }
                    if (e.userJoin)
                    {
                        callback.UserJoin(e.clientJoined);
                        callback.RefreshClients(clientList);
                    }
                    if (e.userLeave)
                    {
                        callback.UserLeave(e.clientLeft);
                        callback.RefreshClients(clientList);
                    }
                    if (e.refreshClients)
                    {
                        callback.RefreshClients(clientList);
                    }
                    if (e.reportDownloadProgress)
                    {
                        callback.UpdateDownloadProgress(e.dwnldPgrsMsg);
                    }
                }
                catch (FaultException ex)
                {
                    MessageBox.Show("FaultException" + e.receiver.Name + ex.Message);
                    Disconnect(c);
                }
                catch (CommunicationException ex)
                {
                    MessageBox.Show("CommunicationException" + e.receiver.Name + ex.Message);
                    Disconnect(c);
                }
                catch (TimeoutException ex)
                {
                    MessageBox.Show("TimeoutException" + e.receiver.Name + ex.Message);
                    Disconnect(c);
                }
                catch (Exception ex)
                {
                    MessageBox.Show("Exception" + e.receiver.Name + ex.Message);
                    Disconnect(c);
                }
            }

    my EndAsync method

    private void EndAsync(IAsyncResult ar)
            {
                ChatEventHandler d = null;

                try
                {
                    //get the standard System.Runtime.Remoting.Messaging.AsyncResult,and then
                    //cast it to the correct delegate type, and do an end invoke
                    System.Runtime.Remoting.Messaging.AsyncResult asres = (System.Runtime.Remoting.Messaging.AsyncResult)ar;
                    d = ((ChatEventHandler)asres.AsyncDelegate);
                    d.EndInvoke(ar);
                }
                catch
                {
                    //ChatEvent -= d;
                }
            }
  • Friday, October 30, 2009 2:33 PMWaldemar Huber Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     
    There must be a strange error I can't see right now. I've tested your scenario with my own small chat program and modified it to not remove closed or faulted clients and then send a message to all in the list. Without try-catch I get an exception only for the one crashed client but if I try next time to send something to all then the whole service is down - it's normal. With try-catch there is no problem. I could still try to send a message to dead clients but the exceptions were catched and only those got the message who are really alive.

    If you want, you can send us your project or modify it to a small sample where you still have the problem.
  • Saturday, October 31, 2009 7:02 AMshaviraghu Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     
    Hi Waldemar,

    I have learnt wcf and developed my application from a freesource project which is at


    I have tested this project and its the same case here.

    But donot have the crashed client and calling client on same machine, have them on different machines and try our scenario. U will see that calling client channel automatically faults.


    Raghu
  • Saturday, October 31, 2009 11:13 AMWaldemar Huber Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     
    Hi Raghu,

    I think I've found the strange bug. I have downloaded and tested the project in your link and could see the same behavior as you described when I just killed a process of some of the clients with taskmanager (you don't need different machines for testing this behavior).

    Here the solution: I don't understand why Microsoft does it this way, but the default WPF application start behavior is a real ****. When you just create a WPF application then you cannot debug normally as you are used like in console or windows forms. I had similar debugging problems a year ago as I had to develop a WPF application. You have to start the main windows by yourself. To do that, you just have to go to the App.xaml and kill the "StartupUri="Window1.xaml"" from the xaml code. Since there is no startup window you have to go to the c# part of App.xaml, add a constructor and start by yourself the Window1 like:

    //constructor
    public App()
    {
         Window1 myWindow = new Window1();
         myWindow.Show();
    }

    From now on you will be able to see and debug all errors. So, if one of your clients crashes, the application will still try to send the message (and also the whisper notification) but you will get an error after 1 minute. In your example application I just used try-catch inside the Say() and Whisper() method and voila, the service lives as long you want him to. In my test scenario I could send and receive messages although one of the clients crashed. But I had always to wait 1 minute because I didn't remove the dead client in my try-catch block.

    I hope I could help you.
    Waldemar
  • Monday, November 02, 2009 6:53 AMshaviraghu Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     
    Hi Waldemar,

    Waldemar the problem is not at service side its only at client side. The server keeps running without any problem after exceptions but the client is one who is affected because his channel is faulted automatically because of exception at server.

    I think we both need some one better to guide us solve or handle this problem since it is new to both of us.

    And please stay glued Waldemar, i will try other resources to solve this problem, if i am successful i would inform u probably through this post.

    I thank u for really trying out ur best to help me eventhough the problem is not yet solved but ur support has been great.

    Thank u again.

    Raghu
  • Monday, November 02, 2009 7:46 AMWaldemar Huber Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     
    Hi Raghu,

    I had really no problems like I described in my last post when I made the described changes. I know that your client is/was dead and not the service, I had the same behavior. And again, as I said in my last post, I was able to keep the service and all connected clients running after the small solution. In my own transport channel in the diploma thesis I have also done some similar test projects to test the new transport channel for serial port ;) it was nothing different. So I wondered why it didn't work when I told you to use try-catch until you posted me the link and I saw that you are using wpf, which has some other problems with debugging when you just use the wpf start project. When you don't do the changes with the starturi in xaml, then you will also some other problems later. In the past when I found this with starturi I didn't have problems with wcf, I didn't know wcf at this time at all, I had some other debugging problems until I killed the starturi und started the window by myself. You can also try to convert the example project to a console application and you will see that you would get an exeption after a timeout which you can catch with try-catch where your service wouldn't kill all the other connections.

    Try the described solution in my post or send me your project. You will see, it works, like it works in all the other projects ;)

    Waldemar
  • Monday, November 02, 2009 10:34 AMshaviraghu Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     
  • Monday, November 02, 2009 12:06 PMWaldemar Huber Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     
    Hi Raghu,

    I don't know what you would like to say with this two links ;) There was nothing new. It's bad when a service throws an uncaught exception, yes, that's what we are talking in this thread. And yes, you can use another proxy which handles exceptions, but it's still only half the solution, because you have to catch the exception on your service too. Each transport causes different exceptions on transport errors, yes. In my own serial transport channel I throw also important transport exceptions, which are bubbled through the whole wcf stack up to user code and where the user cannot just catch the CommunicationException because I'm throwing also some custom exceptions.

    There is another proxy available which generates IL code while the runtime and calls the operations twice. If the real proxy is down then it creates internally a new one and calls the operation again. For my own requirements I modified it also to reinstantiate when the connection has reached the maxReceivedTimeout. I needed it when a long time there was nothing going through channels and where the service would kill the connection because of inactivity. Ofcourse you would have a new connection on error if you use, so you would get a new session if you use sessions. Currently it works only with oneway and reply/request, no duplex.

    http://www.acorns.com.au/blog/Index.php?p=142

    So I don't understand your real problem ;) You catch the exception at the service and kills the dead client on the service side and all things would work like you want them to. If you catch the exception at the service side, your remaining clients wouldn't changed to the faulted state -> killed. If you use WPF, then you have to change startupuri to get the exception thrown and be catchable.

    Waldemar Huber
  • Monday, November 02, 2009 12:50 PMshaviraghu Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     
    Hi Waldemar,

    I have concluded the solution for my problem now based on following points,

    1. We cant alter WCF behaviour of faulting the channel when an exception other than FaultException is thrown by our             service.
    2. WCF sessions are totally dependent on transport layer, which is the first layer becoming useless in sessions by channel     faulting.
    3. So new session needs to be established by creating new proxy.
    4. So all this needs to be handled at client side without any interruption to client user silently in the background.
    5. So am thinking 
        is the apt solution.

    This is what is going on in my mind Waldemar. I am sorry if i am being repeatative or unable to understand u. 

    And i have tried by deleting startupuri from app.xaml and startig window in cs file but no changes in working of client.

    Raghu


  • Tuesday, November 03, 2009 5:24 AMshaviraghu Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     
    Hi Waldemar,

    I am waiting for ur view on what I said.

    Raghu
  • Tuesday, November 03, 2009 8:07 AMWaldemar Huber Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     
    Hi Raghu,

    I have implemented a small example project as a console application just to be clear that I've understand your problem right, since the one wpf example runs without problems. I could face some problems yesterday and then started a new thread. It seems that yesterday there was a strange problem in my work computer. The test project works now fine. Try it and look if it that what you are searching for.

    http://social.msdn.microsoft.com/Forums/en-US/wcf/thread/fe3bd497-99e3-4971-8169-46153f621c8c?prof=required&ppud=4


    To your post: Yes, the sessions are totally depending on the transport layer, but when you have multiple clients and one of them faults then only this one session is dead. There is one channel per session.

    Recreation of the client proxy is nice, yes, but I think that with this approach the main problem is not really solved, it is just by-passed. As you can see in the small example from the link above you can remove the dead client and have not to wait one minute until timeout. Ofcourse the example is for asynchronous calls and I don't know what it would be if there are asynchronous calls. But perhaps you could modify it to asynchronous calls like you have it in your own project. When using tcp your service should be immediately informed about a crashed connection, that is a behavior of tcp.

    What you could try is to set at the client send a higher SendTimeout as on the service. For example: you set on the client 2 minutes SendTimeout and on the service 1 minute. Now, if you face a problem at the service side routing the message to the dead client then you should normally have the one minute timeout and could be able to catch the exception and then notify the calling client about the dead of his partner client.

    Bug again, test the example project and then write to me if it that is what you need.

    Waldemar
  • Tuesday, November 03, 2009 11:15 AMshaviraghu Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     
    Hi Waldemar,

    This is what i wanted Waldemar.I have set sendtimeout at client as 2minutes and at server as 1minute since u advised me the first time in this post. I have looked into your code and i have seen that u have registered two events with server 

    context.Channel.Closed += new EventHandler(delegate
                    {
                        Console.ForegroundColor = ConsoleColor.Red;
                        Console.WriteLine("One channel closed!");
                        Console.ResetColor();
                    });
                    context.Channel.Faulted += new EventHandler(delegate
                    {
                        Console.ForegroundColor = ConsoleColor.Red;
                        Console.WriteLine("One channel faulted!");
                        Console.ResetColor();
                    });

    Here i tried by doing this at my server connect() method,

    ([OperationContract(IsInitiating = true)]
            bool Connect(Client client); this is my connect contract)

    here is my method connect()

    public bool Connect(Client client)
            {
                if (!clients.ContainsValue(CurrentCallback) && !SearchClientsByName(client.Name))
                {
                    myEventHandler = new ChatEventHandler(MyEventHandler);

                    lock (syncObj)
                    {
                        clients.Add(client, CurrentCallback);
                        clientList.Add(client);
                        chatters.Add(client, myEventHandler);
                        OperationContext o = OperationContext.Current;
                        
                        o.Channel.Faulted += new EventHandler(delegate { MessageBox.Show("Client Faulted"); });
                        o.Channel.Closed += new EventHandler(delegate { MessageBox.Show("Client Closed"); });
                        if (clients.Keys != null)
                        {
                            foreach (Client key in chatters.Keys)
                            {
                                ChatEventHandler handler = chatters[key];
                                ChatEventArgs e = new ChatEventArgs();
                                e.person = key;
                                e.clientJoined = client;
                                e.userJoin = true;
                                handler.BeginInvoke(this, e, new AsyncCallback(EndAsync), null);
                            }
                        }
                    }
                    return true;
                }
                return false;
            }

    while client closing event is raised client faulting event is not raised.

    and two at client

                    ((ICommunicationObject)serialService).Closed += new EventHandler(delegate
                    {
                        Console.WriteLine("Service closed!");
                    });

                    ((ICommunicationObject)serialService).Faulted += new EventHandler(delegate
                    {
                        Console.WriteLine("Service faulted!");
                    });

    here as i am using a proxy i dont know how to get an object of type IChat(my server contract).

    i tried it as below

     try
                        {
                            proxy.Endpoint.Address = new EndpointAddress("net.tcp://" +               getIP(serverNameTxtbox.Text).ToString() + ":" + serviceListenPort + servicePath);
                            proxy.Open();
                            IChat id = (IChat)proxy.InnerDuplexChannel;
                            ((ICommunicationObject)id).Closed += new EventHandler(delegate
                            {
                                MessageBox.Show("Service closed!");
                            });

                            ((ICommunicationObject)id).Faulted += new EventHandler(delegate
                            {
                                MessageBox.Show("Service faulted!");
                            });
                        }

    and now closed my server but no event is raised at client.

    Raghu
  • Tuesday, November 03, 2009 2:38 PMWaldemar Huber Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     
    Hi Raghu,

    perhaps the faulted event of the service side is not raised because you close your channel gracefully? Try to kill him with process. Perhaps you have a method which catches the normal application close event and then closes the communication object.

    To your another event problem: Normally it should work with InnerDuplexChannel. It wouldn't work with request/reply channels but with duplex. I tried it out in a small application. I don't like generated proxies but I made a small example. I had first request/reply and it didn't work but with a valid callback contract there is no problem.

    Check the example. Just start service and client and then close the service. I tried also to change the endpoint address and reopen the proxy, but it didn't change anything.

    www.waldemarhuber.de/upload/WCF/ServiceDeathTest.zip

    Waldemar
  • Wednesday, November 04, 2009 7:37 AMshaviraghu Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     
    Hi Waldemar,

    In ur example ServiceDeathTest.zip i am unable to start service it says

    HTTP could not register URL http://+:80/testmex/ because TCP port 80 is being used by another application.

    i dont know how change this since i have app.config file to configure all my service configurations, but i dont see it in ur service.

    waiting for ur reply.

    Raghu
  • Wednesday, November 04, 2009 8:32 AMWaldemar Huber Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     
    Hi Raghu,

    I had a metadata configuration in the *.config file of the service. I needed it for adding the client proxy. Normally I don't use generated proxies.
    I have reuploaded the project, it should work now.

    Btw, it seems that you have something running on port 80. IIS, TeamViewer, Skype or Webserver ;)

    Waldemar
  • Wednesday, November 04, 2009 9:54 AMshaviraghu Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     
    Hi Waldemar,

    this is my proxy handler,

    private void HandleProxy()
            {
                if (proxy != null)
                {
                    switch (this.proxy.State)
                    {
                        case CommunicationState.Closed:
                            proxy = null;
                            stopFileServer();
                            chatListBoxMsgs.Items.Clear();
                            chatListBoxNames.Items.Clear();
                            stopFileServer();
                            //currentDownloadStackPanels.Clear();
                            loginLabelStatus.Content = "Disconnected";
                            ShowChat(false);
                            ShowLogin(true);
                            loginButtonConnect.IsEnabled = true;
                            break;
                        case CommunicationState.Closing:
                            break;
                        case CommunicationState.Created:
                            break;
                        case CommunicationState.Faulted:
                            proxy.Abort();
                            proxy = null;
                            chatListBoxMsgs.Items.Clear();
                            chatListBoxNames.Items.Clear();
                            //currentDownloadStackPanels.Clear();
                            stopFileServer();
                            ShowChat(false);
                            ShowLogin(true);
                            loginLabelStatus.Content = "Disconnected";
                            loginButtonConnect.IsEnabled = true;
                            break;
                        case CommunicationState.Opened:
                            ShowLogin(false);
                            ShowChat(true);
                            chatLabelCurrentStatus.Content = "online";
                            chatLabelCurrentUName.Content = this.localClient.Name;
                            Dictionary<int, Image> images = GetImages();
                            Image img = images[loginComboBoxImgs.SelectedIndex];
                            chatCurrentImage.Source = img.Source;
                            initializeAndStartFileServer();
                            break;
                        case CommunicationState.Opening:
                            break;
                        default:
                            break;
                    }
                }

            }

    these are my registered events which are not raised when service is stopped by user or service crashes

                        proxy.InnerDuplexChannel.Faulted += new EventHandler(InnerDuplexChannel_Faulted);
                        proxy.InnerDuplexChannel.Opened += new EventHandler(InnerDuplexChannel_Opened);
                        proxy.InnerDuplexChannel.Closed += new EventHandler(InnerDuplexChannel_Closed);

    void InnerDuplexChannel_Closed(object sender, EventArgs e)
            {
                if (!this.Dispatcher.CheckAccess())
                {
                    this.Dispatcher.BeginInvoke(DispatcherPriority.Normal, new FaultedInvoker(HandleProxy));
                    return;
                }
                HandleProxy();
            }

            void InnerDuplexChannel_Opened(object sender, EventArgs e)
            {
                if (!this.Dispatcher.CheckAccess())
                {
                    this.Dispatcher.BeginInvoke(DispatcherPriority.Normal, new FaultedInvoker(HandleProxy));
                    return;
                }
                HandleProxy();
            }

            void InnerDuplexChannel_Faulted(object sender, EventArgs e)
            {
                if (!this.Dispatcher.CheckAccess())
                {
                    this.Dispatcher.BeginInvoke(DispatcherPriority.Normal, new FaultedInvoker(HandleProxy));
                    return;
                }
                HandleProxy();
            }


    I have also tried this and it works when service is stopped by user but not when it crashes,

            IChat id = (IChat)proxy.InnerChannel;
            ((ICommunicationObject)id).Closed += new EventHandler(delegate
                            {
                                MessageBox.Show("Service closed!");
                            });

             ((ICommunicationObject)id).Faulted += new EventHandler(delegate
                            {
                                MessageBox.Show("Service faulted!");
                            });


    and the events at the server 

    OperationContext.Current.Channel.Faulted += new EventHandler(delegate { MessageBox.Show(client.Name+" Client Faulted"); });
                        OperationContext.Current.Channel.Closed += new EventHandler(delegate { MessageBox.Show(client.Name +" Client Closed"); });

    are raised when the service is stopped by user.


    waiting for ur reply

    Raghu
  • Wednesday, November 04, 2009 12:07 PMWaldemar Huber Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     
    Hi Raghu,

    did you try my example project and does it worked?

    Waldemar Huber
  • Wednesday, November 04, 2009 12:23 PMshaviraghu Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     
    hi Waldemar,

    Yes ur project is working well. The way i am testing is start the service in debug mode then start client from .exe and
    then crash the service by stopping debugging in visual studio and the client immediately gets notified in ur project.

    But mine doesnt.Is it because urs is console app.

    Raghu
  • Wednesday, November 04, 2009 1:15 PMWaldemar Huber Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     
    Hi Raghu,

    your last code looks ok. If you want you can send me a private message with your code and I would look for the problem. Without the example it's impossible for me, since your code snippets looks ok. You can use admin ||a|t|| waldemarhuber.de

    Waldemar
  • Wednesday, November 04, 2009 1:30 PMshaviraghu Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     
    Hi Waldemar,

    How should i send the code

    Raghu.

  • Wednesday, November 04, 2009 1:43 PMWaldemar Huber Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     
    On my e-mail address given in the last post :)

    Waldemar
  • Wednesday, November 04, 2009 2:15 PMshaviraghu Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     
    Its 59mb i cant send it trough mail

    raghu
  • Wednesday, November 04, 2009 2:25 PMWaldemar Huber Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     
    Hm, it's a bit large :) I think there is not only code but something else like pictures oder sounds. Please send me your email on my given email address, i will then send you a link to my ftp.

    Waldemar Huber
  • Thursday, November 05, 2009 5:21 AMshaviraghu Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     
    Hi Waldemar,

    I am sorry yesterday i was in hurry so i couldnt actually think y it was so big.I have removed those unnnecessary files
    and am sent u my project to your mail id.

    Waiting for my problem to get resolved eagerly.

    Raghu.
  • Thursday, November 05, 2009 10:40 AMWaldemar Huber Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     Answer
    Hi Raghu,

    the problem is the ReliableSession. When you use it then you can kill your host but your clients would not be notified instantly because the ReliableSessionBindingElement would try to reestablish the connection or something like that. After some time the ReliableSession would give up and delegate the error to upper channels/wcf.

    I tried your project without the reliable session and it worked.

    Btw, your clients needs 100% of the CPU. Check your while loops ;) Without them your clients behaved normal.

    I hope I could help you.
    Waldemar Huber
    • Marked As Answer byshaviraghu Thursday, November 05, 2009 12:38 PM
    •  
  • Thursday, November 05, 2009 12:49 PMshaviraghu Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     
    Hi Waldemar,

    Thank u very very much. We finally had a fix. Now i can sleep without any worry.

    And can i go without ReliableSession keeping in mind the kind of application i am developing?

    And about the CPU time thank u for pointing that. As u know i have a fileserver which i ran using a background thread
    to keep it alive i put a while loop which ran till fileserver was closed.I fixed it by hosting it in another hidden WPF window.

    Thank u again Waldemar. U stuck with me for more than a week.  its a great job people like u r doing in this forum.
    For learners like us its people like u who keep us going.

    Waiting for ur reply.

    Raghu.

  • Thursday, November 05, 2009 1:40 PMWaldemar Huber Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     
    Hi Raghu,

    I'm happy too :)

    My opinion about ReliableSession is: This binding element is nice when you have an unreliable transport like UDP, where you cannot be sure if the message arrives or not and whether the messages arrives in the right order. Or perhaps you need a session when you use a sessionless binding. Another good reason for reliable session is when you have a middleman, proxy, delegator, strange router or something like this, where you are not sure if the one would kill some messages or change the order because of some other reasons. If you have a secure, predictable or internal infrastructure or if its not so important, then there is no reason for reliable sessions. Since you are using TCP you have automatically a sessionbased and reliable connection, where your messages arrives in the right order, assured by the tcp protocol.

    One last thing: You may have to implement ping-pong or heartbeat. If you don't then your client connection will be killed after the ReceiveTimeout from the service side when your clients don't send messages. It's at 10 minutes by default. When you send something, regardless of coming from service or client, the timer of ReceiveTimeout will be resettet and the channels have another default 10 minutes to live. You can set the timer to what ever you like, like 10 days, but it's not the best solution. Just create an oneway void heartbeat method and call it within a timer. Don't forget to set the called side to ConcurrencyMode.Reentrant or Multiple to not get a deadlock like when your client calls a normal service method and while this call your timer performs the heartbeat over the callback. You can implement the heartbeat from client or from service.

    Waldemar
  • Thursday, November 05, 2009 1:57 PMshaviraghu Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     
    Hi Waldemar,

    Point noted 

    Hope to meet u again with new issue.

    Nice talking to u.

    Thank u.

    Raghu