After some consideration, I've decided to change the format of this blog. Instead of a blow-by-blow description of every little change to the program - which I now realize was tedious (for me) and unhelpful (for you) - I'm going to try to provide a more in-depth description of a select number of the more interesting problems (and sometimes solutions) I come across. Problem: There are two target markets for our software, one for home and one for schools. The home version uses a local database (like MSDE or SQLServerCE - or the new SQLServer 2005 Express or Mobile), while the school version is a client which stores its data on a server via WebServices - the particular choice of a server will then vary according to the school's infrastructure and budget, from a full-blown SQLServer to MySQL to even MSDE or SQL Server 2005 Express again. That way the school student can move from device to device and find all their data (device here could be a PocketPC, so let's not talking about roaming profiles, eh?) Not a problem yet.
To support this we have an interface (IUploadLocator) which is implemented by two very different looking classes in two different dll's, one for the home version (LocalLib), one for the school (ClientLib). Each is driven by the same class (StudentManager, in a different shared library) and then each communicates hrough its respective channels to the same DBInterface class which knows how to talk to any underlying SQL DB (a story for another day). Is this a problem? Let's examine the chain:
StudentManager -> LocalLib -> DBInterface -> Local SQL DB
StudentManager -> ClientLib -> ASP.NET WebService -> DBInterface -> Server SQL DB
Looks OK, right? Well it was until I threw this into the mix. There are two methods which take a record (StudentsPet.UploadLetterRecord) from StudentManager to feed into DBInterface. Now, when LocalLib sends that to DBInterface, all is well. But when ClientLib tries to send it, ASP.NET screws everything up. It publishes the record from DBInterface as its own type (StudentsPet.Student.localhost.UploadLetterRecord) instead of the common type defined in the DBInterface .dll, as God intended it.
Proposed Solutions: Now I could just unwrap this records into a number of individual parameters, but that creates a a manageability nightmare considering how many layers it traverses (I actually simplified it above), and the fact that I might want to add to the records in the future. Using a DataSet, which somehow manages to flit across ASP.NET boundaries with its type intact, is out both for performance and ugliness reasons.
There must be some way to explain to ASP.NET, perhaps on the server, perhaps on the client, that this type is really that type, no? Applying attributes such as XmlType and SoapType didn't seem to do a thing. I tried changing the namespace, but then I realized that wasn't going to work because it really is a different class.
One system which worked was to extend the partial class in another file (so it won't keep getting wiped out when the webservice updates, duh) with an
implicit conversion function. This worked, but it could introduce subtle errors if I, for instance, add a field to the real version and forget to copy it over in the converter.
Solution: In the end I used a helper method in the record together with a delegate to handle the unwrapping for me, but it doesn't read nicely (taking the method name as a parameter? What is this, Lisp?) and it still has some manageability issues - none which are likely to introduce subtle errors, but issues none the less. I don't like it, but it's the best I have for now.
That was my first post under the new system. Rather inauspicious in that the solution was less than satisfactory, but I think it will be able to get me back into the context quickly if I need to review this code again in the future.