start with reading WCF Performance Using Datasets – Part 1.
Can it be ?
I asked this question over and over – because WCF is clearly faster (see Eyal Vardi comment in part 1). I tried several Binding options including some custom binding , I asked some people to look at my code and up to now no one has manage to contradict my benchmark. I invite each one of you to try (write you own tester) my contract is simple:
public interface IPerfService
DataSet LoadDataSet(DataSet ds);
Why is WCF slower for Datasets ?
I decided to use a profiler and look at the time consuming deviation. I like using Dot Trace profiler because it is very simple and clear. I was sampling one of 1000 iteration after 100 iteration.
Hold tight we are going deep.
You can see that the WCF call (ClientLoadDataSetSelfHost) took 719 ms and the Web Service call (LoadDataSet) took 619 ms
Drilling down I discovered that this gap was a result in the gap of desterilize method duration – makes sense because this is most of the work (DataSet of 15,000 rows).
it’s Important to remember that when serializing / deserializing an object that is implementing IXmlSerializable it doesn’t meter what kind of serializer is defined it will use the object IXmlSerializable implementation – this can be very problematic when using hybrid option when object that not implementing IXmlSerializable holds members that implements IXmlSerializable but discussing this can write full other post.
Both are using: System.Data.DataSet.ReadXml(XmlReader) (from System.Xml.Serialization.IXmlSerializable) – in this function we see the 100 ms diff in duration between Web Service and WCF.
Digging deeper going to the method: System.Data.XmlDataLoader.LoadTable(DataTable, Boolean) called from System.Data.XmlDataLoader.LoadData(XmlReader) called from System.Data.DataSet.ReadXmlDiffgram(XmlReader).
you can see that most of the method takes more time and this is due to the XMLReader specific type that DataSet is choosing in runtime: in web service XMLTextReader in WCF XMLBinaryReader – reading using BinaryXMLReader is taking more time.
When I used text encoding still in WCF it was using XMLBufferReader and not XMLTextReader. In addition I tried most of the binding options but still DataSet is choosing the XMLBufferReader – I’m open for your suggestions. If we could define specific binding that will get DataSet to behave the same as in WebService it could be very useful. The thing is we cannot modify DataSet Code – the XMLReader specific type choosing part.
What is the solution
I’ll start with what is not the solution for sure which is going back to Web Services – we cannot allow our application not moving to WCF because we need WCF power:Security, full separation of binding from service implementation , easy maintaining , tracing ,error handling and most important this is the technology Microsoft is developing and supporting NOW.
I’ll divide my solution to two main options:
- The most correct but annoying solutions: Do not use data set – it’s a large cumbersome out dated object. In addition it’s not strong typed meaning it can cause to fail on runtime. Now the way to go is Domain driven.
I know the fist option is not always possible – sometimes too costly and too risky still this is the way to go.
- DataSet Surrogate – I saw it in several places over the web (here is one). This solution is to hold the all dataset data in other fast serialized object and past the surrogate object over the wire. You can change the WCF method signature to pass this SurrageDataSet or better use Parameter Inspectors (read more here) to do it using WCF extensibility options.
You may encounter the situation of passing DataSets in WCF only on legacy solutions but it’s important that when refactoring old application, you should be aware that moving to WCF not necessary means memory improvement – mainly if all your object model is data sets (very common in legacy solutions).
I implemented and tested my own DataSet surrogate (not supporting relations) and in my bench mark WCF was faster then Web Service in ~15%. I’m sure it depends on number of tables and rows and to rebuild DataSet takes time too. Still I think this can bring significant performance improvement.