Saving data-objects to Isolated Storage in Silverlight

If you are developing an enterprise Silverlight application you will typically need to cache your business entities in the isolated storage. There are two apparent choices for this:

1. Use the powerful Linq-To-XML API from System.Xml.Linq namespace. This method is to be used when you want to have a fine grain control over serialization (e.g. you want to store some properties of the data objects).

2. Use the built-in DataContractSerializer class. This method is very simple and the only thing it requires is that our business objects need to have the [DataContract] and [DataMember] attributes. In this post, I am going to discuss this second method.

In an enterprise LOB (line of business) application, our business objects will typically be retrieved via WCF service and hence will already have the [DataContract] and [DataMember] attributes marked on them. So we can directly use the built-in DataContractSerializer to store them to, and later retrieve them from, the isolated storage. Here’s a generic class to simplify the process:

public static class IsolatedStorageCacheManager<T>
{
    public static void Store(string filename, T obj)
    {
        IsolatedStorageFile appStore = IsolatedStorageFile.GetUserStoreForApplication();
        using (IsolatedStorageFileStream fileStream = appStore.OpenFile(filename, FileMode.Create))
        {
            DataContractSerializer serializer = new DataContractSerializer(typeof(T));
            serializer.WriteObject(fileStream, obj);
        }
    }
    public static T Retrieve(string filename)
    {
        T obj = default(T);
        IsolatedStorageFile appStore = IsolatedStorageFile.GetUserStoreForApplication();
        if (appStore.FileExists(filename))
        {
            using (IsolatedStorageFileStream fileStream = appStore.OpenFile(filename, FileMode.Open))
            {
                DataContractSerializer serializer = new DataContractSerializer(typeof(T));
                obj = (T)serializer.ReadObject(fileStream);
            }
        }
        return obj;
    }
}

Using the above code is really simple. Just add the class to your project and use it like this:

//for storing and retrieving a single object
Person myPersonObj = GetPerson();
IsolatedStorageCacheManager<Person>.Store("myfile.xml", myPersonObj);
Person myPersonObj2 = IsolatedStorageCacheManager<Person>.Retrieve("myfile.xml");

//for storing and retrieving a collection of objects
List<Person> myPersonList = GetPersonList();
IsolatedStorageCacheManager<List<Person>>.Store("myfile.xml", myPersonList);
List<Person> myPersonList2 = IsolatedStorageCacheManager<List<Person>>.Retrieve("myfile.xml");

Hope you will find this implementation useful.

Retrieving huge amount of data from WCF service in Silverlight application

Today, I was trying to figure out why my WCF service call was always throwing the generic NotFound exception when trying to retrieve large datasets. I had all the buffer limits set to 2147483647 (int.MaxValue) at Silverlight service configuration file as well as WCF service configuration section under web.config. Some more analysis revealed that I was getting a System.Net.WebException, saying: The underlying connection was closed: The connection was closed unexpectedly. After some research, I found that I need to set the maxItemsInObjectGraph for dataContractSerializer to some higher value in my web.config.

So, if you are trapped in a similar situation, here are two steps to ensure that you can retrieve large amount of data from WCF service:

1. Enable Silverlight client to retrieve huge chunks of data by enabling large buffers. You need to increase buffer and message size limits for the binding inside ServiceReferences.ClientConfig with something like:

<system.serviceModel>
    <bindings>
        <basicHttpBinding>
            <binding name="BasicHttpBinding_SilverlightWCFService"
                maxBufferSize="2147483647"
                maxReceivedMessageSize="2147483647">
                <security mode="None" />
            </binding>
        </basicHttpBinding>
    </bindings>
    <client>
        <endpoint address="http://localhost:1252/SilverlightWCFService.svc"
            binding="basicHttpBinding" bindingConfiguration="BasicHttpBinding_SilverlightWCFService"
            contract="SilverlightWCFService.SilverlightWCFService" name="BasicHttpBinding_SilverlightWCFService" />
    </client>
</system.serviceModel>

2. Enable WCF service to send large amount of data. You need to set the binding buffer limits as well as tje DataContractSerializer’s maxItemsInObjectGraph value. Here’s an extract from web.config with all the limits set to maximum:

<system.serviceModel>
    <bindings>
        <basicHttpBinding>
            <!-- Create a custom binding for our service to enable sending large amount of data -->
            <binding name="MyBasicHttpBinding"
                maxBufferPoolSize="2147483647"
                maxReceivedMessageSize="2147483647"
                maxBufferSize="2147483647">
                <readerQuotas
                    maxArrayLength="2147483647"
                    maxBytesPerRead="2147483647"
                    maxDepth="2147483647"
                    maxNameTableCharCount="2147483647"
                    maxStringContentLength="2147483647" />
            </binding>
        </basicHttpBinding>
    </bindings>

    <behaviors>
        <serviceBehaviors>
            <!-- Enable the serializer to serialize greater number of records -->
            <behavior name="SilverlightWCFLargeDataApplication.Web.SilverlightWCFServiceBehavior">
                <serviceMetadata httpGetEnabled="true"/>
                <serviceDebug includeExceptionDetailInFaults="false"/>
                <dataContractSerializer maxItemsInObjectGraph="2147483647"/>
            </behavior>
        </serviceBehaviors>
    </behaviors>

    <serviceHostingEnvironment aspNetCompatibilityEnabled="false"/>
    <services>
        <!-- Bind the WCF service to our custom binding -->
        <service behaviorConfiguration="SilverlightWCFLargeDataApplication.Web.SilverlightWCFServiceBehavior"
                name="SilverlightWCFLargeDataApplication.Web.SilverlightWCFService">
            <endpoint address="" binding="basicHttpBinding"
                bindingConfiguration="MyBasicHttpBinding"
                contract="SilverlightWCFLargeDataApplication.Web.SilverlightWCFService"/>
            <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>
        </service>
    </services>
</system.serviceModel>

That was all related to sending greater amount of data from WCF service to Silverlight application. However, if you want to send large amount of data from Silverlight to WCF service, you need one more step as you can reach the maximum permitted http request length limit (this is 4MB by default). This again can be solved by tweaking the web.config. E.g. to allow 10MB data, you need something like:

  <httpRuntime maxRequestLength="10240" />

That’s all. Let’s enjoy developing LOB applications with this great platform.