Performance is a vital part for any application possibly more important for web based app. With wizard based approach of RIA service, generally we tends to comprise all entities, exposing to the client and also allowing the DomainService
to go for everything from the database. Not only does this approach take a toll on security, but also it loads the middle tier unreasonably.
So this post is about few tips using which we can improve the performance. Well, mostly, we will cover the Pagination, Limiting Query results and Output cache of the results.
The Example
As we need a database with records that really exist in real world scenario. I am going to stick with Adventure Database example database from Microsoft. As mentioned in my earlier post, more details regarding the database can be found here. Also, you can download database samples from codeplex with the following links AdventureWorksLT 2005 version, AdventureWorksLT 2008 version. For presentation model scenario, I am going to use a part of the Data Model which involves Customer
and Address
.
And we will use the same sample as mentioned in my Presentation Model article.

Before beginning with the performance measures, allow me to put some light on basic configurations and coding of the project. In this example, the DataBinding
is achieved declaratively through DomainDataSource
control. The DomainDataSourceControl
code is as follows:
<riaControls:DomainDataSource AutoLoad="True"
d:DesignData="{d:DesignInstance my:CustomerPresentationModel, CreateList=true}" Height="0"
LoadedData="customerPresentationModelDomainDataSource_LoadedData"
Name="customerPresentationModelDomainDataSource"
QueryName="GetCustomersWithAddressQuery" Width="0">
<riaControls:DomainDataSource.DomainContext>
<my:ADVWORKDomainContext />
</riaControls:DomainDataSource.DomainContext>
</riaControls:DomainDataSource>
The next step is bind the DomainDataSource
to the Item Source of DataGrid
:
<sdk:DataGrid AutoGenerateColumns="False" Height="468"
ItemsSource="{Binding ElementName=customerPresentationModelDomainDataSource, Path=Data}"
Margin="0,66,0,0" Name="customerPresentationModelDataGrid"
RowDetailsVisibilityMode="VisibleWhenSelected" VerticalAlignment="Top">
<sdk:DataGrid.Columns>
<sdk:DataGridTextColumn x:Name="addressIDColumn"
Binding="{Binding Path=AddressID}"
Header="Address ID" Width="SizeToHeader" />
<sdk:DataGridTextColumn x:Name="addressLine1Column"
Binding="{Binding Path=AddressLine1}"
Header="Address Line 1" Width="SizeToHeader" />
<sdk:DataGridTextColumn x:Name="addressLine2Column"
Binding="{Binding Path=AddressLine2}"
Header="Address Line 2" Width="SizeToHeader" />
<sdk:DataGridTemplateColumn x:Name="addressModifiedDateColumn"
Header="Address Modified Date" Width="SizeToHeader">
<sdk:DataGridTemplateColumn.CellEditingTemplate>
<DataTemplate>
<sdk:DatePicker SelectedDate="{Binding Path=AddressModifiedDate,
Mode=TwoWay, NotifyOnValidationError=true, ValidatesOnExceptions=true}" />
</DataTemplate>
</sdk:DataGridTemplateColumn.CellEditingTemplate>
<sdk:DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding Path=AddressModifiedDate, StringFormat=\{0:d\}}" />
</DataTemplate>
</sdk:DataGridTemplateColumn.CellTemplate>
</sdk:DataGridTemplateColumn>
<sdk:DataGridTextColumn x:Name="cityColumn" Binding="{Binding Path=City}"
Header="City" Width="SizeToHeader" />
<sdk:DataGridTextColumn x:Name="customerIDColumn"
Binding="{Binding Path=CustomerID, Mode=OneWay}" Header="Customer ID"
IsReadOnly="True" Width="SizeToHeader" />
<sdk:DataGridTemplateColumn x:Name="customerModifiedDateColumn"
Header="Customer Modified Date" Width="SizeToHeader">
<sdk:DataGridTemplateColumn.CellEditingTemplate>
<DataTemplate>
<sdk:DatePicker SelectedDate="{Binding Path=CustomerModifiedDate,
Mode=TwoWay, NotifyOnValidationError=true, ValidatesOnExceptions=true}" />
</DataTemplate>
</sdk:DataGridTemplateColumn.CellEditingTemplate>
<sdk:DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding Path=CustomerModifiedDate, StringFormat=\{0:d\}}" />
</DataTemplate>
</sdk:DataGridTemplateColumn.CellTemplate>
</sdk:DataGridTemplateColumn>
<sdk:DataGridTextColumn x:Name="emailAddressColumn"
Binding="{Binding Path=EmailAddress}"
Header="Email Address" Width="SizeToHeader" />
<sdk:DataGridTextColumn x:Name="firstNameColumn"
Binding="{Binding Path=FirstName}"
Header="First Name" Width="SizeToHeader" />
<sdk:DataGridTextColumn x:Name="lastNameColumn"
Binding="{Binding Path=LastName}"
Header="Last Name" Width="SizeToHeader" />
<sdk:DataGridTextColumn x:Name="phoneColumn"
Binding="{Binding Path=Phone}"
Header="Phone" Width="SizeToHeader" />
<sdk:DataGridTextColumn x:Name="postalCodeColumn"
Binding="{Binding Path=PostalCode}"
Header="Postal Code" Width="SizeToHeader" />
<sdk:DataGridTextColumn x:Name="stateProvinceColumn"
Binding="{Binding Path=StateProvince}"
Header="State Province" Width="SizeToHeader" />
</sdk:DataGrid.Columns>
</sdk:DataGrid>
Performance Snapshot – Before
Using Visual Studio Profiler Wizard with CPU sampling, the snapshot shows the elapsed time for calling the query and fetching the detail from the database.The straight forward approach to RIA service with Domain DataSource
control it retrieves all 800 records at one shot.

Well, a detailed tutorial about performance wizard in Visual Studio 2010 can be found here.
Performance Tips and Tricks
As the number of records returned by the query always have a performance impact over the web, so the following tips and tricks in combination proper coding standard always make a difference - let's discuss a few of them.
Pagination with LoadSize and PageSize
The first step of improvements lies with applying paging to the data. Well, paging works without DomainDataSource
control but it works better with DomainDataSource
control. So let's add a DataPager
control to the page and bind the source to Domaindatasource
control.
<sdk:DataPager Height="26"
Margin="0,0,0,44" Name="dpCustomers"
PageSize="10" VerticalAlignment="Bottom"
DisplayMode="FirstLastPreviousNextNumeric" AutoEllipsis="False"
Source="{Binding Path=ItemsSource,ElementName=customerPresentationModelDataGrid}"/>
Although the paging option will start working, still we are loading everything from the database so we need to make some tweaks to the DomainDataSource
control.

As mentioned in the above image, LoadSize
loads exactly specified amount of records with each hit to the Tier interaction. For the next 30 records, it hits the database again.

So here with the above snap shot from Tier Interaction, you can find out for each record after 30th the DomainDataSource
control is sending fresh request to fetch the next set.
While working with LoadSize
and page Size, make sure that the PageSize
of Datapager
and DomainDataSource
control are the same, here in this example it's defined as 10
. Also, make sure the page size is less than the LoadSize
.
Limit Results of Query Operation
Instead of fetching all the details, try using QueryAttribute
to limit the results from the query operation. Domain Service at server side supports attribute to limit the result set. For example, here in this example, each call to domain service returns maximum 30 results.

Well, make sure that your loadsize
and pagesize
as mentioned in above tips for Datapager
must be with in this limit. Well, it is worth mentioning that one of my readers was facing issues, the famous LoadOperation
failed and on digging a bit, we found that the real problem was timeOut
. Once we set the ResultLimit
, the project was on the run.
Caching of Output
Well this option really is not meant for real time data where changes are very frequent but you can always cache the output of a method call using attributes.

As shown above, OutoutCacheLocation
specifies the location where the resource needs to be cached.
Performance Snapshot – After
Well, we talked much and now it's time for the result. As mentioned above, the TierInteraction
gives you a complete picture of time taken by each method call.

Comparison of Performance
The last call where you can compare both performance results lets you show a complete picture over the improvement.

The Delta here shows a sharp increment in performance of Tier Interaction for GetCustomerWithAddress
query method.
Conclusion
May be there is a lot of scope available for performance improvement such as exposing entities that need to be exposed to the client by using Presentation Model and few tricks over native WCF service but for the time being, I hope the above will make a difference. Keep suggesting your ideas and comments.