A
while back, I remember being asked if there was a simple way to expose a source XML document as an object with properties. That is, if the root XML element had a child element <Name>Doug</Name>, then the object would have a Name property that was a string and returned “Doug”. The catch was that the XML document did not conform to a specific schema. Hence, you could not simply create an object with a Name property, because you did not know if the source document had a <Name> element. While there are ways to expose the XML data dynamically, you couldn’t quite do what was being asked.
Enter dynamic objects in Visual Basic 2010. Now, this is possible. This means that you can use the classes in the System.Dynamic namespace to create objects that expose properties and methods dynamically at run-time and solve the original problem. In this example, we will create an object that inherits the System.Dynamic.DynamicObject class. The DynamicObject class has methods that you can override to provide code specific to your implementation. When VB performs a late-bound request on an object that implements the DynamicObject class, it calls one of the methods of the DynamicObject class to obtain the result. Consider this simple example:
Imports System.Dynamic
Public Class SimpleObject
Inherits DynamicObject
Public Overrides Function TryGetMember(ByVal binder As GetMemberBinder,
ByRef result As Object) As Boolean
If binder.Name = “Address” Then
result = “Value”
Return True
End If
Return False
End Function
End Class
Now consider this code that creates an instance of the object and accesses properties of that instance.
Module Module1
Sub Main()
Dim t As Object = New SimpleObject()
Console.WriteLine(t.Address)
Console.WriteLine(t.Street)
End Sub
End Module
First, in order to ensure that requests made of the dynamic object are late-bound, we need to type the variable as Object. Then we make two late-bound requests for object properties: Address and Street. When you access the Address property, a call is made to the TryGetMember method of the DynamicObject class, which we have overridden. The GetMemberBinder object instance that is passed to our TryGetMember method contains the name of the requested member in its Name property. Our small sample matches that name and returns the string “Value”. When you access the Street property, a call is made to the TryGetMember method, the name does not match anything that our code supports, so the method returns False. False indicates an unsupported member, and an exception is thrown.
To solve our initial problem of “hiding” source XML and exposing an object instead, we can use the DynamicObject class in this same fashion. When a property is requested of our dynamic object, our code can search the XML source for a matching XML element name, and return the corresponding value as the property value. Let’s look at an example.
DynamicXmlObject example
Let’s jump into the code and we’ll talk about how the object behaves as we go. We start with a class that inherits DynamicObject. Let’s name it DynamicXmlObject.
Imports System.Dynamic
Public Class DynamicXmlObject
Inherits DynamicObject
End Class
Constructors
We will add two constructors for the class. One that takes a path to an XML file as the source, and another that takes an XElement. The constructor that takes an XElement is not just for user convenience. We’ll use this later when dealing with child elements that have attributes or children. Also for this class, we won’t expose a settable property for the source XML, so we’ll “disable” the empty constructor by making it Protected.
Imports System.Dynamic
Imports System.IO
Public Class DynamicXmlObject
Inherits DynamicObject
‘ The source XML for this instance.
Private p_Xml As XElement
‘ Create a new DynamicXmlObject with the specified source file.
Public Sub New(ByVal filePath As String)
If Not File.Exists(filePath) Then
Throw New Exception(“File does not exist.”)
End If
p_Xml = XElement.Load(filePath)
End Sub
‘ Create a new DynamicXmlObject with the specified source XElement.
Public Sub New(ByVal xml As XElement)
p_Xml = xml
End Sub
‘ Disable the empty constructor.
Protected Sub New()
End Sub
End Class
Implementing GetDynamicMemberNames
This next piece of code is optional. I’ve added it so that our object supports reflection-like functionality. You can expose the member names of your dynamic object using the GetDynamicMemberNames method of the DynamicObject class. Our sample object will return all of the child element names and attribute names of the current element. I’ve added a case-insensitive Distinct comparison so that only a single name is returned if multiple entries are found. The search looks at only the LocalName property of the XName for an element or attribute. XML namespaces are ignored. That is, <a:Name> and <b:Name> are considered to be duplicate element names.
Public Overrides Function GetDynamicMemberNames() As IEnumerable(Of String)
Dim names = (From e In p_Xml.Elements() Select e.Name.LocalName).Union(
From a In p_Xml.Attributes() Select a.Name.LocalName)
Return (From n In names
 
Hi Doug
Just came across this article while looking for a solution to my problem. Hope you could guide me well.
In the process of implementing a wrapper for web sessions (i.e. HttpContext.Current.Session) for my library, I got hit by two problems:
1. Having "Option Strict On" vomits while attempting to use the object. e.g.
Dim ws As Object = New MyLibrary.WebSessionWrapperClass
ws.UserName = "Username" (this throws the compiler to disallow late binding)
2. I have to instantiate the class everytime I need to access the session thru my wrapper, thus defeating my intentions to obtain friendly access to the web session contents.
What could be the right (politically correct) way of achieving my objective?
Thanks / @bhi
Is your Session state configured with a server rather than InProc?
Nopes. It is InProc. I don't really need a state server / SQL server for our apps. We don't rely too much on session state, just a few handy bits of info which can be easily re-populated, if required.
And yes, I was able to solve my problem #2 yesternight. I did that by using a singleton instance pattern instead of a completely shared (static) class and methods. It works like a charm!
My problem #1 still remains however.
I have to switch "Off" the "Option Strict" to make it work. But, this then leaves me vulnerable to possible nightmares of debugging an accidental narrow conversion scenario. Besides, I might slip in an occasional VB specific code (like forgetting to CChar a string character) and resulting in non-CLS-compliant code.
I feel safe and secure when "Option Strict" is on. However, am at a loss to find a way out with Dynamic Objects.
In your project properties on the "Compile" tab you can configure the individual parts of the Option Strict setting project-wide including which aspects are legal, and which are warnings/errors. If you want to allow late-binding (Dynamic) without allowing implicit conversions set the project setting to Strict On and then set the "Late binding; call could fail at runtime" setting to either warning or none. This will allow you to use late-binding project wide without allowing implicit conversions.
-ADG
I may be missing some details, but I don't think Dynamic objects is the solution. Is there a reason you can't just cast the object with Option Strict On?
Dim ws As MyLibrary.WebSessionWrapperClass = _
TryCast(Session("mySession"), MyLibrary.WebSessionWrapperClass)
When I work with Session objects, I prefer to get the Session data into a page-scope variable for the duration of the page, and save at the end of the page code if necessary.
Hmmm..
Thanks ADG, I think that should suffice just fine! I have checked it and it does serve my purpose well. Thanks again. It was right there, staring at my face all the time and I didn't pay attention!!
VBTeam/Doug: Yes, I know it is an overkill for session obejcts. But, I wanted to put Dynamic to test and some use in my current project. Moreover, this provides me with a way to use session variables fluently.
So rather than having this splattered across all pages / library code:
CInt(HttpContext.Current.Session("SomeNumber"))
I can now have:
WS.Current.SomeNumber.ToInt
Where "Current" is the Shared (static) method that instantiates and returns an object of WS class.
Thank you guys again for all the help.
Another pattern you might try using that I've used in the past is to create a base class for all (or most) pages in your web project (see P of EAA: Layer Supertype).
What I do is make my own class called Page that Inherits System.Web.UI.Page and then make sure all the aspx code-behind classes inherit from my Page class. This way you get all of the normal behavior of a normal ASPX page but you get a class you can control in between the basic ASP.NET Page and all of your pages where you can add common functionality so you don't have to duplicate it on all of your pages.
For example, if you did this in your project you could Shadow the Session property in *your* Page class and define a new Session property that always returns your strongly-typed Session object. You'd only have to do it once and all of your pages could just say Session.SomeNumber without having to worry about the plumbing or calling into Shared singletons. And if you have common page validation logic to run OnLoad of the page you can control that in one place 🙂
-ADG