CodeBetter.Com
CodeBetter.Com
RSS 2.0 via Feedburner
           Do you Twitter? Follow us @CodeBetter

Grant Killian's Blog

No, this has nothing to do with beer -- but maybe it should?

Web Service gotcha: DataSet.HasErrors HasProblems

I've spent the last few hours wrestling with the issue identified in Microsoft KB Article 818587; in a nutshell, serialized DataSet objects that have Row or Column Errors can have trouble when passed between web services to client consumers.  My specific case is an Excel-based data editor (using VSTO) that relies on Web Services for transmitting data to and from the data server. 

Everything was going great until I started expanding the proof-of-concept to handle concurrency exceptions -- I'm dutifully using a SqlRowUpdatedEventHandler to manage concurrency errors and after I kept getting NullReferenceExceptions after passing the DataSet with the Errors back to the client, I discovered KB Article 818587.  At this point I scratched my head some and thought this through: this isn't your typical KB Resolution from Microsoft, it says “To resolve this problem, contact Microsoft Product Support Services to obtain the fix.“  It goes on to indicate the resolution is to install a new System.Data assembly, which sounds innocent on it's own, but this will throw the configuration management folks here (and more importantly, at the client) into fits. 

A thought occurred to me: since it's 1) late in the evening and I don't feel up to a Microsoft call and 2) pretty certain our customer will not like having to run a special “patched“ System.Data dll just for this app, why don't I try to program my way out of this paper bag?

I decided to circumvent the native Web Service serialization and try my own, to see if I could get my DataSet to successfully transfer between server and client without the magic dll from Microsoft.  I created a Serialization Helper class to convert any object into a serialized string (note: I used the very verbose SoapFormatter instead of the BinaryFormatter to ensure that my string transfers without loss of data -- yes it's slower but in this case it's a necessary evil):

  public static string getSerializedVersion( object obj )
  {
   System.Runtime.Serialization.Formatters.Soap.SoapFormatter soap =
    new System.Runtime.Serialization.Formatters.Soap.SoapFormatter() ;
   byte[] buf ;
   System.IO.MemoryStream mem = new System.IO.MemoryStream() ;
   soap.Serialize( mem, obj ) ;
   buf = mem.ToArray() ;
   return System.Text.UTF8Encoding.UTF8.GetString( buf ) ;
  }
 

You may think: isn't this what the SOAP plumbing for Web Services does already?  Conceptually, I think that's true, but there's obviously some magic in my manual serialization of the object since it succeeds where the intrinsic Web Service serialization fails with the nasty NullRef XML exception.  This may be a bit slower, but I'll take slower code that runs over fast code that doesn't really work any day!  By the way, for this to work you'll need to reference System.Runtime.Serialization.Formatters.Soap.dll in your project.

To use this SerializationHelper class, we can just do the following to return a string from our web method:

    theDataAdapter.Update( theDataSet ) ;
    return SerializationHelper.getSerializedVersion( theDataSet ) ;

The flip side to this is that the client has to specially deserialize our DataSet; we can use a SerializationHelper class to do something like the following (this time I'll show VB.Net since our client using Excel is written in VB.Net, sorry C# purists, see this post for why!):

 dim strResult as string = objWebSvc.getDataSetWithPotentialErrors()
 dim soap as New System.Runtime.Serialization.Formatters.Soap.SoapFormatter()
 dim buf as byte() = System.Text.UTF8Encoding.UTF8.GetBytes( strResult )
 dim mem as IO.MemoryStream = new IO.MemoryStream( buf )
 dim obj as Object = soap.Deserialize( mem )
 theDataSet = CType( obj, DataSet )

OK, so where does this get me?  I've managed to avoid calling Microsoft and aggravating our customer with a special System.Data assembly requirement for the project; I think I've programmed myself out of the paper bag in time to watch the Daily Show on Comedy Central! 

I'm sure somebody from my company will contact Microsoft about the KB Resolution and our work-around, to see what the whole story is.  If it's worthwhile, I'll post a follow up.  Until then, I'm content with this approach.  I've spent some time in the various newsgroups and I'm not the only one who wrestled with this known issue, perhaps this will prevent you from spinning your wheels too long on it.

Happy .Netting!



Leave a Comment

(required)  
(optional)
(required)  

Enter the numbers above:
Add
Check out Devlicio.us!