Data transfer speed issues for WindowsForms/WPF in 4.5.20

Data transfer speed issues for WindowsForms/WPF in 4.5.20

Old forum URL: forums.lhotka.net/forums/t/11905.aspx


tiago posted on Wednesday, March 27, 2013

Hi Rocky,

I have this test application that started life on CSLA .NET 2.xx using Windows Forms. Since the business and the data access are generated, I made it evolve to CSLA .NET 4.3.13 and now there are also WPF and Silverlight versions. These two versions used the same ViewModels and almost the same Views.

I have a form/view that is a ReadOnly list of ReadOnly objects. In the database there are 500.000 rows but I only fetch 10.000 at a time.

For 10.000 rows, under 4.3.13 the timings are:
WindowsForms/WPF: 12.5 sec
WindowsForms/WPF binary formater: 4 sec
Silverlight: < 2 sec

For the same 10.000 rows, under 4.5.20 the timings are.. the same!!!

Except I can't use the binary formater. So the net result of upgrading to 4.5.20 is that my application runs slower!

I was under the very strong impression that upgrading to CSLA 4.5 would result in WindowsForms/WPF using the same lightning fast serializer/formater used by Silverlight. I even thought this was the only serializer/formater available on CSLA 4.5.

I tried a lot of configuration settings but the numbers didn't change.

Why do the WindowsForms/WPF versions take 6 times more than the Silverlight one, to transfer the exact same data? What am I doing wrong?

<edit>

I tried CSLA .NET 4.5.20 targeting NET 4.0 and NET 4.5 and the results are the same.

</edit>

tiago replied on Thursday, March 28, 2013

Final update and request for help

There are no samples that use mobile serializer/formater, except for Silverlight/WP/WinRT. My problem concerns NET so...

This NET 4.5 project has clients for Silverlight, WPF and Windows Forms. Let's forget about Windows Forms for a moment.

The project is a migration of a CSLA 4.3.13 and so there are only synchronous DataPortal_XYZ methods (the ones that return void). This shoudn't be a problem since everything works when using WcfProxy.

When I switch the WPF client to MobileProxy (I founf out how to do it), some classes behave as they should, some other classes just hang the WPF client application.

I know the MobileProxy is being used because the view referred above loads 10.000 rows in less than 2 seconds, but I can't login (the list is available for everyone).

I don't think this is related to BO code, as the same code works all right under Silverlight (that is using the Mobile serializer/formater) and when I use WcfProxy.

So... I need help. What are the correct configuration options? Could this be a new bug?

RockfordLhotka replied on Saturday, March 30, 2013

It is possible that there are bugs of course :)

Version 4.3 didn't automatically use the new binary reader/writer - you need to configure the client and server to use them. This is discussed in the change log for the version where this was introduced (4.1?).

In 4.5 we changed the default behavior to use the new reader/writer.

tiago replied on Saturday, March 30, 2013

Hi Rocky,

The new MobileFormatter was introduced in 4.3.0 and according to

http://www.lhotka.net/Article.aspx?id=1c287e08-d428-4c27-b538-d588e3c55775

it was available only for Silverlight and Windows Phone.

On the appserver web.config we had to add to the appSettings block

<add key="CslaWriter" value="Csla.Serialization.Mobile.CslaBinaryWriter, Csla" />
<add key="CslaReader" value="Csla.Serialization.Mobile.CslaBinaryReader, Csla" />

On the Application_Startup method of App.xaml.cs of Silverlight and Windows Phone projects we had to add

Csla.Serialization.Mobile.CslaReaderWriterFactory.SetCslaReaderType(typeof(Csla.Serialization.Mobile.CslaBinaryReader));
Csla.Serialization.Mobile.CslaReaderWriterFactory.SetCslaWriterType(typeof(Csla.Serialization.Mobile.CslaBinaryWriter));

That works all right. Some configuration changes were needed in order to keep it working on 4.5.20. I had a look at the ProjectTracker projects and made the necessary adjustments. But that's not the point. My SIlverlight projects is using the so called binary reader/writer under 4.3.13 and 4.5.20 and works all right on both scenarios. The problem is my NET applications under 4.5.20: both WPF and Windows Forms stop working as they should when I try to use the mobile formatter.

Let me add that while WPF half works (some views do, some other don't), Windows Forms is completely broken. The view that works on WPF uses a ReadOnlyList while in Windows Forms the equivalent form uses a ReadOnlyBindingList. This shouldn't be important but I can't find any other difference at all.

By the way, I find the naming quite confusing, since binary formatter is the standard Microsoft .NET, the one we can find on System.Runtime.Serialization.Formatters.Binary.BinaryFormatter. On the above link to 4.3.0 release notes, you can see that Issue 984 refers a CslaFormatter "that is more efficient than MobileFormatter". So all of a sudden we have 3 names for the same formatter:

As far as I can see by looking at 4.5.20 source code, the correct name is MobileFormatter.

Again, as far as I can see by looking at 4.5.20 source code, the MobileProxy uses the MobileFormater and so does the WcfPortal you can find on Csla.Server.Hosts.Mobile. Simple, consistent and makes sense.

There are no samples that use this scenario for WPF or Windows Forms. This is important because when in doubt, we turn to samples. So either I have misconfigured something or it doesn't work.

RockfordLhotka replied on Tuesday, April 02, 2013

Ahh, I suspect I know the issue then.

The BusinessListBase class is modern, and has always had to work with MobileFormatter.

BusinessBindingListBase is for legacy support of Windows Forms and never had to work with MobileFormatter in the past.

It is very likely that the ___BindingListBase classes use private backing fields and/or don't include the IMobileObject implementations required to work with the MobileFormatter.

That is a bug of course. One most easily solved by eliminating support for Windows Forms - if only I could do that... :)

RockfordLhotka replied on Wednesday, April 03, 2013

Now I think my suspicion is wrong. Mostly because I created a simple test app using the MobleProxy and I'm not having any problems with the data portal or serialization with BusinessBase or BusinessBindingListBase.

Can you create a simple repro of the issue?

Basically try what I just did - create a new UI project, class library, and web project. Set them up for n-tier configuration using the MobileProxy and host, and retrieve some objects of various stereotypes.

tiago replied on Friday, April 05, 2013

Hi Rocky,

What are the correct configurations? Can you confirm the configuration changes below?

Windows Forms app.config

<appSettings>
  ...
  <add key="CslaDataPortalProxy" value="Csla.DataPortalClient.MobileProxy, Csla"/>
</appSettings>
<system.serviceModel>
  <!-- The default is basicHttpBinding. Is wsHttpBinding needed or the default will do as well-->
  <client>
    <endpoint name="WcfDataPortal" binding="wsHttpBinding" bindingConfiguration="wsHttpBinding_IWcfPortal" address="http://localhost:33725/WcfPortal.svc" contract="WcfPortal.IWcfPortal"/>
  </client>
  <bindings>
    <wsHttpBinding>
      <binding name="wsHttpBinding_IWcfPortal" maxReceivedMessageSize="2147483647" maxBufferPoolSize="2147483647" receiveTimeout="10" sendTimeout="10" openTimeout="10">
        <readerQuotas maxBytesPerRead="2147483647" maxArrayLength="2147483647" maxStringContentLength="2147483647" maxNameTableCharCount="2147483647" maxDepth="2147483647"/>
      </binding>
    </wsHttpBinding>
  </bindings>
</system.serviceModel>

WcfPortal.svc

<% @ServiceHost Service="Csla.Server.Hosts.Mobile.WcfPortal" %>

WcfAppServer web.config

<appSettings>
  <!-- Is this needed at all? -->
  <add key="CslaWriter" value="Csla.Serialization.Mobile.CslaBinaryWriter, Csla"/>
  <add key="CslaReader" value="Csla.Serialization.Mobile.CslaBinaryReader, Csla"/>
</appSettings>
<services>
  <service name="Csla.Server.Hosts.Mobile.WcfPortal" behaviorConfiguration="returnFaults">
    <endpoint binding="wsHttpBinding" bindingConfiguration="wsHttpBinding_IWcfPortal" contract="Csla.Server.Hosts.Mobile.IWcfPortal"/>
  </service>
</services>

 

RockfordLhotka replied on Saturday, April 06, 2013

Close.

The client no longer needs the system.servicemodel stuff at all - just set the data portal url via appsettings and it does the right thing.

The server does still need all the system.servicemodel stuff to set the data size limits to max (I assume you have that but didn't show it).

In CSLA 4.5 you do not need to set the cslareader/cslawriter because they default to binary.

tiago replied on Saturday, April 06, 2013

There may be some big misunderstanding because when I apply the configuration changes to the trunk's project tracker it just hangs.

WfUI app.config

<add key="CslaDataPortalProxy" value="Csla.DataPortalClient.MobileProxy, Csla"/>

WcfAppServer WcfPortal.svc

<% @ServiceHost Service="Csla.Server.Hosts.Mobile.WcfPortal" %>

What am I missing?

RockfordLhotka replied on Saturday, April 06, 2013

On the client I have this:

  <appSettings>
    <add key="CslaDataPortalProxy" value="Csla.DataPortalClient.MobileProxy, Csla"/>
    <add key="CslaDataPortalUrl" value="http://localhost:17270/SlPortal.svc"/>
  </appSettings>

On the server I have this:

  <system.serviceModel>
    <serviceHostingEnvironment multipleSiteBindingsEnabled="true" />
    <services>
      <service behaviorConfiguration="WcfPortalBehavior" name="Csla.Server.Hosts.Mobile.WcfPortal">
        <endpoint address="" binding="basicHttpBinding" contract="Csla.Server.Hosts.Mobile.IWcfPortal" bindingConfiguration="basicHttpBinding_IWcfPortal">
          <identity>
            <dns value="localhost" />
          </identity>
        </endpoint>
        <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
      </service>
    </services>
    <bindings>
      <basicHttpBinding>
        <binding name="basicHttpBinding_IWcfPortal" maxReceivedMessageSize="2147483647">
          <readerQuotas maxBytesPerRead="2147483647" maxArrayLength="2147483647" maxStringContentLength="2147483647" maxDepth="1024" />
        </binding>
      </basicHttpBinding>
    </bindings>
    <behaviors>
      <serviceBehaviors>
        <behavior name="returnFaults">
          <serviceDebug includeExceptionDetailInFaults="true" />
        </behavior>
        <behavior name="">
          <serviceMetadata httpGetEnabled="true" />
          <serviceDebug includeExceptionDetailInFaults="false" />
        </behavior>
        <behavior name="WcfPortalBehavior">
          <serviceMetadata httpGetEnabled="true" />
          <serviceDebug includeExceptionDetailInFaults="true" />
        </behavior>
      </serviceBehaviors>
    </behaviors>
  </system.serviceModel>

RockfordLhotka replied on Saturday, April 06, 2013

One other thing to note is that Windows Forms defaults the current principal to the .NET GenericPrincipal. That type can't be serialized through the MobileFormatter, so you must ensure your app's current principal is set to some valid object as the app starts. I typically do this:

      Csla.ApplicationContext.User = new Csla.Security.UnauthenticatedPrincipal();

tiago replied on Saturday, April 06, 2013

After the changes to *.config files on the master branch ProjectTracker, WPF UI can login and shows data. Even after the fix for Windows Forms principal, its UI can't login and it doesn't show any data at all.

tiago replied on Saturday, April 06, 2013

RockfordLhotka

One other thing to note is that Windows Forms defaults the current principal to the .NET GenericPrincipal. That type can't be serialized through the MobileFormatter (...)

If a type can't be serialized, shouldn't the serializer raise an exception?

tiago replied on Saturday, April 06, 2013

On my test project WPF I wasn't able to login using the MobileProxy. As soon as I changed the ViewModel class to use BeginLogin() instead of the synchronous Login() the problem was solved.

This project was migrated from 4.3.13 with minimal changes and doesn't use async/await keywords.

Everything works when I used WcfProxy.

Windows Forms uses only synchronous methods.

Some forms that work under Silverlight, hang under WPF when using the MobileProxy.

No form works under Windows Forms when using the MobileProxy.

RockfordLhotka replied on Saturday, April 06, 2013

I wonder if you have proper exception handling code? The serializer _does_ throw an exception if it can't serialize or deserialize an object - that's what reminded me about the principal (because as soon as I ran my little test app it blew up).

Is it possible that you are getting exceptions from the data portal and are swallowing them so you don't see the reason for failure?

tiago replied on Saturday, April 06, 2013

No try/catch block are used. Then again, the exceptions should also show on ProjectTracker WfUI project and I saw none. Why don't you try to port ProjectTracker to MobileProxy?

tiago replied on Saturday, April 06, 2013

RockfordLhotka

One other thing to note is that Windows Forms defaults the current principal to the .NET GenericPrincipal. That type can't be serialized through the MobileFormatter, so you must ensure your app's current principal is set to some valid object as the app starts. I typically do this:

      Csla.ApplicationContext.User = new Csla.Security.UnauthenticatedPrincipal();



 

On my test project I added then removed the line above. Then I checked the default value of

Csla.ApplicationContext.User

is indeed Csla.Security.UnauthenticatedPrincipal. That's why I don't get a serialization exception.

I made brakpoints on all four exceptions that are thrown on the MobileFormatter class. After I click on the login button, execution never stops on any of the breackpoints.

I manage to force an exception by inserting the lines below in the MobileFormatter class, in the public SerializationInfo SerializeObject(object obj) method

if (obj.GetType() == typeof (Csla.Core.MobileList<string>))
  mobile = null;

right after

var mobile = obj as IMobileObject;

Running (CTRL F5) with this change I get a "Type MobileList`1 must implement IMobileObject" exception

So my UI app shows exceptions.

RockfordLhotka replied on Saturday, April 06, 2013

It is possible that the issue is related to this

https://github.com/MarimerLLC/csla/issues/66

I assume your calls are sync (DataPortal.Fetch, not FetchAsync)?

tiago replied on Sunday, April 07, 2013

As sync as it can be.

I'm using DataPortal.Fetch (not BeginFetch nor FetchAsync):

RockfordLhotka replied on Sunday, April 07, 2013

OK, it is a sort of related issue, but is really this:

https://github.com/MarimerLLC/csla/issues/114

tiago replied on Thursday, April 11, 2013

It's almost solved. The forms/views show all right. There is this issue about a DynamicRoot not invalidating the cache (it works with the WcfProxy but doesn't with the MobileProxy).

Copyright (c) Marimer LLC