locked
UI becoming much slower in the MVVM pattern using wcf service asynchronously RRS feed

  • Question

  • Hi Guys,

    Something tricky happen to me while I try to use WPF MVVM pattern with WCF service.

    I host my WCF service in three seperate servers, say server1, server2,server3. In my client-side, invoke one operation on these servers, one after another, asynchronously, to see if any of them is not available. If one server is down(the server maybe not power on), then I catch the exception(I get TargetInvocationException, InnerException, EndpointNotFoundException, WebException), and notify the UI that the server not found.

    Things are going on pretty smoothly while my client is a winform application, but in a WPF app with the MVVM partern, UI getting frozen and not responding for about 20~30 seconds while the exception be caught, then recovered and continue.  Dose any one know why?

    Code snippets bellow:

    (This is where I invoke the operation asynchronously)

      ServiceClient  sClient = new ServiceClient();
      sClient.GetDataCompleted += sClient_GetDataCompleted;
      sClient.GetDataAsync();
     

    (Bellow is the event handler, where the exceptions are caught)

    void sClient_GetDataCompleted(object sender, GetDataCompletedEventArgs e)

                {
                DataInfo dataInfo;
                try
                    {
                    DataInfo = e.Result;
                    //do something.
                    }
                catch(Exception)
                    {
       //do something to handle the exception.
       //It is in this place, the UI frozen.
                    }
                finally
                    {
                    ServiceClient client=sender as ServiceClient;
                    if(client.State == CommunicationState.Opened)
                        {
                        client.Close();
                        }
                    }

    Code above are in the ViewModel. In the catch(Exception) block, the UI will freeze even I did nothing at all. If I did anything in the background thread, the UI usaully not frozen except the exception was a WCF EndpointNotFoundException.

    I already posted this message to the WCF forum, but not yet solve the problem.

    Regards,

    Tony


    Tony Zeng qzcbs@163.com
    Friday, July 15, 2011 3:53 PM

Answers

  • An interesting thing happens in WPF land when bound data begins to be rendered.  It get's bogged down!  So the solution to that is to limit the amount of data being displayed at one time.  There are many ways to do this, but they are homegrown unless you are into Silverlight which has a paging control. 

    The idea to to only show what can be shown on a single view.  Anything additional has to be refreshed from datastore.  LINQ has some really nice Take commands that allow you to only "TAKE" x amount of records from a collection at a time.  It's ideal for this type of issue.

    WPF Rendering is slower than Winforms IMO.  But it's versatility is 100 times nicer.  If this isn't your issue, then you are not using async in conjuntion with the Viewmodel (property store) correctly.  Sounds like you are though.


    JP
    • Marked as answer by Tony Zeng Thursday, July 21, 2011 5:56 AM
    Sunday, July 17, 2011 7:13 AM

All replies

  • Hi Tony.

    You should use Exception blocks only on places where you cannot go without that exception. I think that when you implement try, catch that makes the CLR much slower(in your case to UI freeze). Also notice the big difference between how WPF and windows forms work .There was an advice in one of the first books i read about .net, to use exception block only if it is a must.  http://msdn.microsoft.com/en-us/library/ms229009.aspx here is very nice article about the performance issue. Good luck with coding, hope that information helps!

    Dimitar.




    Saturday, July 16, 2011 8:37 AM
  • Hi Tony,

    I have made asynchronous call to WCF from WPF app by follwoing code-

      private void fun()
            {
                 GreetWorldClient client = new GreetWorldClient("BasicHttpBinding_GreetWorld");
                client.BeginGreet("test", delegate(IAsyncResult ar)
                {
                    string result = "";
                    try
                    {                  
                        result = client.EndGreet(ar);
                        label1.Dispatcher.Invoke((Action)(() => label1.Content = result), null);
                        throw new Exception();
                    }
                    catch
                    {
                        client.Close();
                        Thread.Sleep(5000);
                        client = new GreetWorldClient("NetTcpBinding_GreetWorld");
                        result = client.GreetNew("New", "Values");
                        label1.Dispatcher.Invoke((Action)(() => label1.Content = result), null);
                    }
                  

                }, null);
            }

    By the above code UI never freezes, please try this and let me know if find difficulty.

     

    Saturday, July 16, 2011 9:05 AM
  • Hi Tony,

    I have made asynchronous call to WCF from WPF app by follwoing code-

      private void fun()
            {
                 GreetWorldClient client = new GreetWorldClient("BasicHttpBinding_GreetWorld");
                client.BeginGreet("test", delegate(IAsyncResult ar)
                {
                    string result = "";
                    try
                    {                  
                        result = client.EndGreet(ar);
                        label1.Dispatcher.Invoke((Action)(() => label1.Content = result), null);
                        throw new Exception();
                    }
                    catch
                    {
                        client.Close();
                        Thread.Sleep(5000);
                        client = new GreetWorldClient("NetTcpBinding_GreetWorld");
                        result = client.GreetNew("New", "Values");
                        label1.Dispatcher.Invoke((Action)(() => label1.Content = result), null);
                    }
                  

                }, null);
            }

    By the above code UI never freezes, please try this and let me know if find difficulty.

     


    Hi, sanguin,

    What you show above in your code is what I did in my previous winform apps, where we are interacting with the UI object (here in your code is the label1) directly, and the UI never freezes. But I'm now using the MVVM patterns which is a very loosely coupled design, with a ViewModel class connected to the UI through data binding, then every update to the UI will be done by modifying the properties of this ViewModel class. This appraoch have many benefit so I don't want to return to my old programming patterns.

    Here is the article when I first learn MVVM,http://msdn.microsoft.com/en-us/magazine/dd419663.aspx


    Tony Zeng qzcbs@163.com
    Sunday, July 17, 2011 6:52 AM
  • Hi Tony.

    You should use Exception blocks only on places where you cannot go without that exception. I think that when you implement try, catch that makes the CLR much slower(in your case to UI freeze). Also notice the big difference between how WPF and windows forms work .There was an advice in one of the first books i read about .net, to use exception block only if it is a must.  http://msdn.microsoft.com/en-us/library/ms229009.aspx here is very nice article about the performance issue. Good luck with coding, hope that information helps!

    Dimitar.





    Thank you DimitarGeorgiev. Of course exceptions can negatively impact performance in this case,  but I'm still not sure if it is the main reason that make the CLR much slower. I will study the article you posted and do some further test to try to find out what is going on.
    Tony Zeng qzcbs@163.com
    Sunday, July 17, 2011 7:04 AM
  • An interesting thing happens in WPF land when bound data begins to be rendered.  It get's bogged down!  So the solution to that is to limit the amount of data being displayed at one time.  There are many ways to do this, but they are homegrown unless you are into Silverlight which has a paging control. 

    The idea to to only show what can be shown on a single view.  Anything additional has to be refreshed from datastore.  LINQ has some really nice Take commands that allow you to only "TAKE" x amount of records from a collection at a time.  It's ideal for this type of issue.

    WPF Rendering is slower than Winforms IMO.  But it's versatility is 100 times nicer.  If this isn't your issue, then you are not using async in conjuntion with the Viewmodel (property store) correctly.  Sounds like you are though.


    JP
    • Marked as answer by Tony Zeng Thursday, July 21, 2011 5:56 AM
    Sunday, July 17, 2011 7:13 AM
  • An interesting thing happens in WPF land when bound data begins to be rendered.  It get's bogged down!  So the solution to that is to limit the amount of data being displayed at one time.  There are many ways to do this, but they are homegrown unless you are into Silverlight which has a paging control. 

    The idea to to only show what can be shown on a single view.  Anything additional has to be refreshed from datastore.  LINQ has some really nice Take commands that allow you to only "TAKE" x amount of records from a collection at a time.  It's ideal for this type of issue.

    WPF Rendering is slower than Winforms IMO.  But it's versatility is 100 times nicer.  If this isn't your issue, then you are not using async in conjuntion with the Viewmodel (property store) correctly.  Sounds like you are though.


    JP

    Hi, I'm not displaying a great amount of data to the UI. Actually, I only update a string property constantly in my viewmodel, and I did this successfully in my other wpf applications, and those apps are similar to this one on both implement a WCF-WPF-MVVM pattern. This is why it really confuse me.

     


    Tony Zeng qzcbs@163.com
    Sunday, July 17, 2011 8:11 AM
  • Ok Tony, so as was suggested before why have exception logic in call back.  Shouldn't the result of the callback always guarantee good data or a semiphore suggesting bad data instead of trying to catch exception?  That's why Async almost always has a time-out associated with it (because you just can't wait forever on something that may never show)...
    JP
    Sunday, July 17, 2011 9:02 PM
  • But even so, if your callback is on a different thread than GUI you can get around the Exception checking too.  Just use events to signal the Viewmodel after the Exception checking is done that data is ready...
    JP
    Sunday, July 17, 2011 9:03 PM
  • Hi Tony,

     

    The code I provided above is just an example, if you remove the line-

      label1.Dispatcher.Invoke((Action)(() => label1.Content = result), null);

    by-

    _vm.Property1 = client.GreetNew("New", "Values");

     

    [update viewmodel's property which implements INotifyPropertyChanged or DependencyProperty]

    still it never causes UI to hang.

    Please try and let me know if still face problem.

    Monday, July 18, 2011 10:06 AM
  • Yes, I was going to ask "much slower" than what?  Winforms?  Or non MVVM WPF?
    JP
    Monday, July 18, 2011 3:44 PM
  • Ok Tony, so as was suggested before why have exception logic in call back.  Shouldn't the result of the callback always guarantee good data or a semiphore suggesting bad data instead of trying to catch exception?  That's why Async almost always has a time-out associated with it (because you just can't wait forever on something that may never show)...
    JP

    Yes, I'm thinking to put all my WCF operations invoke logic to a background thread to see if it can solve this, but not yet have the time to try this since other project pressures and many codings needed to test this thought. But anyway, thank you very much to join me together on this topic, and after I get anything, will let you know result of that.
    Tony Zeng qzcbs@163.com
    Wednesday, July 20, 2011 10:22 AM
  • Hi Tony,

     

    The code I provided above is just an example, if you remove the line-

      label1.Dispatcher.Invoke((Action)(() => label1.Content = result), null);

    by-

    _vm.Property1 = client.GreetNew("New", "Values");

     

    [update viewmodel's property which implements INotifyPropertyChanged or DependencyProperty]

    still it never causes UI to hang.

    Please try and let me know if still face problem.


    It still facing problems if your WCF client can not find the endpoint (EndPointNotfoundException), even you invoke WCF service operations asynchronously.
    Tony Zeng qzcbs@163.com
    Wednesday, July 20, 2011 10:26 AM
  • Yes, I was going to ask "much slower" than what?  Winforms?  Or non MVVM WPF?
    JP

    Than Winforms.
    Tony Zeng qzcbs@163.com
    Wednesday, July 20, 2011 10:26 AM
  • Can you provide a sample code of your problem.
    Wednesday, July 20, 2011 11:58 AM
  • Can you provide a sample code of your problem.

    Sample code was already provided in my original post.
    Tony Zeng qzcbs@163.com
    Thursday, July 21, 2011 2:36 AM
  • An interesting thing happens in WPF land when bound data begins to be rendered.  It get's bogged down!  So the solution to that is to limit the amount of data being displayed at one time.  There are many ways to do this, but they are homegrown unless you are into Silverlight which has a paging control. 

    The idea to to only show what can be shown on a single view.  Anything additional has to be refreshed from datastore.  LINQ has some really nice Take commands that allow you to only "TAKE" x amount of records from a collection at a time.  It's ideal for this type of issue.

    WPF Rendering is slower than Winforms IMO.  But it's versatility is 100 times nicer.  If this isn't your issue, then you are not using async in conjuntion with the Viewmodel (property store) correctly.  Sounds like you are though.


    JP

    You are terribly right! My data get bogged down, and this time, is when using the MetadataExchangeClient.BegingGetMetadata(), though this is a asynchronous invacation and my breadpoints shows that the code block responsable for updating the UI is working well in the background, the UI is still not responding.
    Tony Zeng qzcbs@163.com
    Thursday, July 21, 2011 5:56 AM
  • Yes it's not to hard to simulate this issue using MVVM.  If you have an ObservableCollection of something that is really large, but an aysnc model callback, you can actually prove that the callback returns that data beautiful (say it's already of the same type of data such as already and ObservableCollection).  From the moment the property is set and the change notification goes out and when the data is displayed is well, it's delayed.  Although I have never compared the results, I just seemed to remember Winforms was a lot faster.

    But....because WPF is so cool, I will continue to find ways to handle this problem and I hope you can find something that works for you.  I personally don't want to ever return to Winforms.


    JP
    Thursday, July 21, 2011 9:59 PM
  • I personally don't want to ever return to Winforms.
    JP

    100% agree.
    Tony Zeng qzcbs@163.com
    Sunday, July 24, 2011 5:50 PM