Owing a debt of gratitude to Jan Tielens
I’m in the design phase of a new project and I’m doing proof-of-concept viability testing for several different n-tier scenarios. One of those scenarios entailed using an ASP .NET web application as the front end, making calls to a WebService as the Business rules layer, which in turn managed the conversion of SQL Server data into typed class objects. The idea here is that the Front End application should have no need to understand the underlying layout of the database.
One of the first issues I ran into is that the class objects that a web service returns to a calling app are really nothing more than glorified structures. They cannot contain methods for functions. They basically only have public fields. This may be old news to many of you, but I’m new to web services, so although it makes perfect sense in hindsight, it was quite a shocker at the beginning.
The second issue I ran into was the inability to databind a dropdownlist to an array of classes received from the webservice. I posted a question to Microsoft.public.dotnet.framework.aspnet.webservices newsgroup, and received a reply from Jan Tielens, which referred me to this article. Long story short, when the VS .NET IDE creates the webservice proxy , it creates any classes with public fields instead of public properties. In other words, given a class defined as:
Public Class Test
Public Property ThisIsATest as string
Return “This Is A Test of the Emergency Broadcast System.”
End Property
End Class
The Proxy class will contain a client-side definition such as:
Public Class Test
Public ThisIsATest as String
End Class
This wouldn’t be a problem, except that databinding a dropdownlist only works for Properties, not public fields. I wonder if any MS people could say if there is a technical reason for this, or if it’s simply an oversight?
Jan's article has a novel solution to the problem, however. It contains dll code which will receive an array of classes as an argument. It will retrieve the underlying type of the array elements, create a new proxy class which converts any public fields into public properties, and returns the new array to the calling function—all of this at runtime. From there, databinding is a cinch.
As slick as the above code is, I had to modify it somewhat to get it to work in the my web app environment. It contains a call to System.Reflection.Assembly.GetEntryAssembly which apparently only returns an assembly when the calling assembly is a windows forms application. In my case, it returned Nothing. I replaced this call with System.Reflection.Assembly.GetAssembly(typeToWrap) instead. I also rebuilt the code in VB .NET since that’s what we code in here. Jan, if you would like a version of the code in VB .NET, I would be happy to send it to you.
This was the final technical hurdle toward evaluating one possible implementation of our n-tier design. This is what I have working right now:
1) A UI page written for ASP .NET begins to load, making a call to a webservice for information to display.
2) The webservice then executes a query on the underlying database, which returns its results as an XML document.
3) The webservice then deserializes that XML document directly into a structured, hierarchical class structure, which is returned to the calling ASP .NET webpage.
4) The calling webpage then gets the array of items it wants to bind a dropdownlist to, but can’t because all of the properties have been converted to fields.
5) Instead, the code passes said array into Jan Tielen’s dll where some very interesting magic occurs.
6) Reflection is used to compile a new assembly, in memory, replacing the auto-generated fields with properties, and returning a typed array of nearly identical class objects, public fields replaced by public properties.
7) This new array is then databound to the dropdownlist easily.
How cool is that?
Thanks Jan! Your article was a great help—a fantastic piece of coding on your part! In addition, you've taught me how to dynamically add functionality to classes at runtime, and my mind is reeling with the possibilities!