Welcome

You have reached the blog of Keith Elder. Thank you for visiting! Feel free to click the twitter icon to the right and follow me on twitter.

Tips: Using Strong Typed DataSets with Web Services

Posted by Keith Elder | Posted in Uncategorized | Posted on 23-02-2007

Before I start this article, let me be up front and state that I do not use DataSets 100% of the time.  I do use the heck out of them in demos and presentations because, well, they demo well.  There is a never ending debate on whether to use DataSets or not.  I say use them, but not in all situations.  That’s my official stance on them.  In a lot of cases they make sense, espeically when doing binding to a DataGrid and reconciling changes, in others they don’t.  We are not here today to argue for or against them though.  What I will share with you are some tips that many may or may not know when using DataSets with Web Services.   

Tip #1:  Include Only What You Need

As the tip states, include only the tables you need.   I never create one master DataSet with all of my tables from my Database.  I find it to be hard to work with and typically if I am working on a module basis which means I don’t need everything anyway, just the tables that apply to the module I am working with.  I see a lot of time where people create DataSets where they include the entire database in a DataSet.  I don’t, especially for modules.  A lot of the time I will have a DataLayer that is made up of several different DataSets, not one large one.  Here’s an example of what I’m talking about:

 

This example from the AdventureWorks database has only two DataTables in it:  Contact and ContactType.  This is all I need if I am going to deal with a Contact.  It is easier to manage and look at, and less of a code footprint.   If you are passing this information over a web service, by default, the schema of the DataSet goes along for the ride.  Having more tables, means more schema information, which brings me to my second tip.

Tip #2:  Don’t Include Schema Information

If you are using a Strong Typed DataSet, before you return your DataSet from a Web Service, mark it to not include the schema.  Here is a sample web method using the Strong Typed DataSet seen above.

       [WebMethod]

        public ContactDataSet GetContactsByLastname(string lastname)

        {

            DataLayer.ContactDataSetTableAdapters.ContactTableAdapter ta = new DataLayer.ContactDataSetTableAdapters.ContactTableAdapter();

            ContactDataSet ds = new ContactDataSet();

            ds.Merge(ta.GetByLastName(lastname));

            return ds;

        }

 Here is the output from this web method saved to the file system. 

The majority (95%) of what is in the file is the Schema Definition for the DataSet.  This is why the file is 5.23KB.  The only part we *really* want is the row data.  This is one of the major reasons people stay away from DataSets.  Which is a shame since they provide a lot of functionality.  It turns out we can fix this problem with one line of code.  Here is the new code sample whereby we exclude the schema:

        [WebMethod]

        public ContactDataSet GetContactsByLastname(string lastname)

        {

            DataLayer.ContactDataSetTableAdapters.ContactTableAdapter ta = new DataLayer.ContactDataSetTableAdapters.ContactTableAdapter();

            ContactDataSet ds = new ContactDataSet();

            ds.Merge(ta.GetByLastName(lastname));

            ds.SchemaSerializationMode = SchemaSerializationMode.ExcludeSchema;

            return ds;

        }

 If we run this example which excludes the XSD, we immediately see a smaller footprint.  We go down from 5.23KB to 1.54KB:

And here is the output from the web service.  Much much smaller than previous, and it contains the data we primarily care about althought it does include a few straglers which I would like to see removed entirely from future versions.  Maybe the .Net team can add a new flag to the enumeration which is SechamSerializationMode.JustGiveMeMyData. 🙂

<?xml version=1.0 encoding=utf-8?>

<ContactDataSet msdata:SchemaSerializationMode=ExcludeSchema xmlns:msdata=urn:schemas-microsoft-com:xml-msdata xmlns=http://keithelder.net/>

    <xs:schema id=ContactDataSet targetNamespace=http://tempuri.org/ContactDataSet.xsd xmlns:mstns=http://tempuri.org/ContactDataSet.xsd xmlns=http://tempuri.org/ContactDataSet.xsd xmlns:xs=http://www.w3.org/2001/XMLSchema xmlns:msdata=urn:schemas-microsoft-com:xml-msdata attributeFormDefault=qualified elementFormDefault=qualified>

        <xs:element name=ContactDataSet msdata:IsDataSet=true msdata:UseCurrentLocale=true>

            <xs:complexType>

                <xs:choice minOccurs=0 maxOccurs=unbounded />

            </xs:complexType>

        </xs:element>

    </xs:schema>

    <diffgr:diffgram xmlns:msdata=urn:schemas-microsoft-com:xml-msdata xmlns:diffgr=urn:schemas-microsoft-com:xml-diffgram-v1>

        <ContactDataSet xmlns=http://tempuri.org/ContactDataSet.xsd>

            <Contact diffgr:id=Contact1 msdata:rowOrder=0>

                <ContactID>19978</ContactID>

                <NameStyle>false</NameStyle>

                <FirstName>Keith</FirstName>

                <LastName>Elder</LastName>

                <EmailAddress>not@telling.com</EmailAddress>

                <EmailPromotion>1</EmailPromotion>

                <PasswordHash>hash</PasswordHash>

                <PasswordSalt>salt</PasswordSalt>

                <rowguid>cd9ea7c0-d192-4a9f-9999-e9a0c6b117a9</rowguid>

                <ModifiedDate>2007-01-30T11:16:48.703-06:00</ModifiedDate>

            </Contact>

        </ContactDataSet>

    </diffgr:diffgram>

</ContactDataSet>

Note, if you are using plain datasets, you have to include the schema, always.

 Tip #3:  Enable GZIP on IIS

The last tip while not exclusive to DataSets is worthy of noting nontheless.  That is to turn on Gzip compression in IIS.   You will notice a drastic performance increase of data moving over the wire.  XML compresses really well with Gzip and I’ve seen 20K or 26K messages get turned in 2-4K easily.  For smaller messages you may don’t want to Gzip since it will actually add to the message footprint.  The good news is when you create your proxy class to call the web service, you can choose if you want to support it or not.  Here’s an example:

 

MyService proxy = new MyService();
proxy.EnableDecompression = true;

This is supported in .Net 2.0.  The above lines will set the HTTP header when the service is called to tell IIS that Gzip compression is supported and IIS will then zip the contents and send them back down.  If you have a very small message then set this to false, otherwise you will add overhead of the compression. 

Technorati tags: , , , , ,

Like This Article?  kick it on DotNetKicks.com

Comments (11)

If you use the ExcludeSchema then you won’t get the schemas for other tables.

Thanks for the reply. So even if you use ExcludeSchema, you still get table definitions for those tables that dont include data? I guess this would give relevance to your first point to only include in the dataset those tables you need… thanks again for your help

@kevin

The dataset I think is going to carry the entire schema. So even if you only send data from one table, it is going to send all schema information back.

is there a difference between the schema information and the schema for the actual table? for example. if you have several tables in a dataset, does the table schema get passed back for all tables, and just not schema information for those tables? it seems like this may be the case… does anyone know?

This article is good.The data given was excellent.That can easily understand by the user.

Good stuff with the ExcludeSchema and the compression.

The only time I’ve ever gotten the Out of Memory exception was when in fact I was returning a million records from a web service (I was testing, no flames please). The data came down the wire just fine but when it got to the client, it physically ran the client out of memory. Obviously this was way more than 30MBs but I wasn’t using WSE with the call.

Actually the images aren’t messed up, but the point isn’t coming across clearly. I’m going to remove it for clarity. Thanks.

As I have found out the hard way, using DataSets while great, also has serious problems. No matter how you go about it, there is a hard limit of about 30 megs of data. This isn’t because of DataSets, it’s because of the System.Text.StringBuilder and also encryption level events that happen while serializing the data (especially with WSE). Even if you allow huge uploads and downloads, it will still crash with an out of memory exception.

So if you know that you’ll never send more than 30 megs at a time, great. But if you’re not sure, get ready to chunk your data… it’s ugly, but there isn’t any other way around it currently because of the bugs in StringBuilder and the encryption classes.

(BTW, this comment entry form is completely screwed in IE 7 on Vista…)

Just a quick heads up – you seem to have gotten your images of the xml file outputs mixed up. No big deal but you may want to switch them around the right way.

Cheers.

You’ve been kicked (a good thing) – Trackback from DotNetKicks.com

Write a comment