Tuesday, April 21, 2009

ASP.Net HTTPRequest.Cookies and HTTPResponse.Cookies Analyzed

One thing that confuses many new ASP.net developers (and even well seasoned ones too!) is understanding the difference between Request.Cookies and Response.Cookies. It is very easy to dismiss this as a simple answer. Request.Cookies are the cookies that the browser sent to IIS and the Response.Cookies are what will be sent back to the browser. That is all fine and dandy, right?

Most developers would make an assumption the HttpRequest.Cookies is a static point in time capture of what was sent from the browser. So then you go and add a cookie to the Response.Cookies collection and bam what happens? The Request.Cookies collection has changed! What? It was static right? And that right there is what makes it not so black and white. And the MSDN documentation fails to mention this any where.

So here are some conclusions that I have made using Redgate's Reflector product to look at the System.Web assembly.

HttpRequest.Cookies Get Property
- Looks at private member _cookies and returns it if not nothing
- HttpCookies collection created with Friend (Internal) constructor that takes HttpResponse and a read only flag which a set to Nothing and True, respectively. A function is called to populate _cookies from the HTTP headers and the collection is returned.

HttpResponse.Cookies Get Property
-- Looks at private member _cookies and returns it if not nothing
-- HttpCookies collection created with Friend (Internal) constructor that takes HttpResponse and a read only flag which are set to current Response and False, respectively. Empty collection is returned

HttpRequest.Cookies("NonexistentCookieName") returns nothing because the HttpCookies collection internal member _response is nothing.

HttpResponse.Cookies("NewCookieName") creates a new Cookie because response is not nothing. i.e., this is why any key sent through HttpResponse gets a new cookie object.

So there a two separate HTTPCookie collections. HTTPCookie collection is flagged to know if it is a collection of Request cookies or Response Cookies. Simple and pretty standard so far. Now, here is the twist.

HttpResponse.Cookies("NewCookieName") not only creates a new cookie but also calls Me._response.OnCookieAdd(cookie).

HttpResponse.OnCookieAdd calls Me.Request.AddResponseCookie(cookie).

Wait a second! Adding a cookie to the Response collection also adds the same cookie object to the HttpRequest.Cookies collection? But, HttpRequest is the static read-only version sent from the browser. Right? That is what I thought and many others. And that is why there are so many questions on cookies in the forums. People are not just stupid knuckle heads asking the same dumb question over and over. This doesn't make sense!

And here is another thing....
Let's say you already have a cookie and you want to modify the value.

HttpResponse.Cookies("ExistingCookieName").Value = "NewValue"

Guess what? HttpRequest.Cookies now has two entries for "ExistingCookieName". One with the old value and one with the new value.

For the life of me, I cannot figure out why the Request.Cookies collection is changed and/or what benefit doing so provides.

I could understand that when a brand new cookie is added, other code in the same response call can also find the value in the Request. But why not the same when a cookie is modified, why have two conflicting values in Request.Cookies?

Also note that HttpResponse.AddCookie and HttpResponse.SetCookie are marked as infrastructure in MSDN so they should not be used. But for the record AddCookie calls the Me.OnCookieAdd(cookie) which adds the Cookie to the HttpRequest.Cookies collection, however SetCookie does not.

So in conclusion the Description for HttpRequest.Cookies "Gets a collection of cookies sent by the client." is a lie. It is updated by changes to the HttpResponse.Cookies collection and I have proof by looking at the source code. I will continue my mission to find out why....... There must be some logical answer out there somewhere....

P.S. Here is a method that I wrote that somewhat alleviates the issue.

    Public Sub SetCookieValue(ByVal cookieName As String, ByVal cookieValue As String)
        'Try to get existing cookie if it already exists.
        Dim c As HttpCookie = HttpContext.Current.Request.Cookies(cookieName)
        If c Is Nothing Then
            'Cookie did not already exist so create a new one
            HttpContext.Current.Response.Cookies(cookieName).Value = cookieValue
            'The above call also adds the cookie to the Request.Cookies collection.
        Else
            'Cookie already exists in Request collection, so use it.
            c.Value = cookieValue
            HttpContext.Current.Response.Cookies.Add(c)
            'There will be two entrees in Request.Cookies, but they will point to same object.
        End If
    End Sub
kick it on DotNetKicks.com

Thursday, January 22, 2009

SQL Server 2008 Error: SetParent Falied for DataFile

When creating a SQL 2008 database through SSMS, I wanted to add a File for the new FileStream type. I kept getting an error dialog box stating:
TITLE: Microsoft SQL Server Management Studio
------------------------------

SetParent failed for DataFile 'test'.  (Microsoft.SqlServer.Smo)

For help, click: http://go.microsoft.com/fwlink? 
ProdName=Microsoft+SQL+Server
&ProdVer=10.0.1600.22+((SQL_PreRelease).080709-1414+)&EvtSrc=Microsoft.SqlServer.Management.Smo.ExceptionTemplates.
   FailedOperationExceptionText
&EvtID=SetParent+DataFile&LinkId=20476

------------------------------
ADDITIONAL INFORMATION:

Value cannot be null.
Parameter name: newParent (Microsoft.SqlServer.Smo)
The Microsoft help link came up empty and so did a Google search. I had been previously using a SQL script to create the database, but this time I was determined to make it work through the GUI. I found the problem was that I didn't go to the FileGroup tab first and add a FileStream FileGroup.

Wednesday, September 24, 2008

Period Key Closes Dialog Box in Visual Studio

I had an issue in the Workflow Rule Set Editor dialog box in Visual Studio 2008 SP1 while entering a Condition pressing the period (or dot) key would suddenly close the window. I tracked it down to being an Intellisense issue since it was only occurring after an object name was typed followed by the period key. However in the code designer Intellisense was working fine. Through trial and error, I found that removing my Project References and re-adding them made the problem go away.

Wednesday, August 27, 2008

LINQ Aggregates – Max() and Min() with no results from Where clause

I started getting the error “Sequence contains no elements” today and tracked the issue down to a LINQ statement in my code. It turns out that this was coming from the Max aggregate function that was operating on a filtered row set that had no matches.
Here is a simplified recreation of the problem I was having.
Module Module1
    Private Structure test
        Public Key As String
        Public Value As Integer
    End Structure

    Sub Main()
        Dim myList As New List(Of test)
        myList.Add(New test() With {.Key = "A", .Value = 1})
        myList.Add(New test() With {.Key = "A", .Value = 2})
        myList.Add(New test() With {.Key = "A", .Value = 3})
        myList.Add(New test() With {.Key = "B", .Value = 1})
        myList.Add(New test() With {.Key = "B", .Value = 2})
        myList.Add(New test() With {.Key = "C", .Value = 1})

        'Get Max Value of the A values -- Res1 is set to 3
        Dim Res1 = Aggregate t In myList Where t.Key = "A" Into Max(t.Value)

        'Get Max Value of the D value, which doesn't exist in the data collection
        Dim Res2 = Aggregate t In myList Where t.Key = "D" Into Max(t.Value)
        'This will fail with "Sequence contains no elements" error

        'Yet the SUM aggregate function works without error and sets Res3 to 0
        Dim Res3 = Aggregate t In myList Where t.Key = "D" Into Sum(t.Value)
    End Sub
End Module
As you can see on Res2 the “Sequence contains no elements” error occurs because the WHERE clause eliminates any rows for the Max function to process. Also this error occurs with the Min and Average functions as well. However other Aggregate functions such as Any, All, and surprisingly Sum all work without complaining. The Sum function just returns a 0 if there are no values. I wish Min and Max did the same.
My initial fix was to abandon the Max function and just sort the results descending and take the first result.
Module Module2 'Forget Max and just sort results and take first value
    Private Structure test
        Public Key As String
        Public Value As Integer
    End Structure

    Sub Main()
        Dim myList As New List(Of test)
        myList.Add(New test() With {.Key = "A", .Value = 1})
        myList.Add(New test() With {.Key = "A", .Value = 2})
        myList.Add(New test() With {.Key = "A", .Value = 3})
        myList.Add(New test() With {.Key = "B", .Value = 1})
        myList.Add(New test() With {.Key = "B", .Value = 2})
        myList.Add(New test() With {.Key = "C", .Value = 1})

        'Create a blank list for testing
        Dim blankList As New List(Of test)

        'Res1 will be 3
        Dim Res1 = (From t In myList Where t.Key = "A" Order By t.Value Descending Select t.Value).FirstOrDefault()

        'Res2 will be 0 because there is no "D" key
        Dim Res2 = (From t In myList Where t.Key = "D" Order By t.Value Descending Select t.Value).FirstOrDefault()

        'Res3 will be 0 because the list is blank
        Dim Res3 = (From t In blankList Where t.Key = "A" Order By t.Value Descending Select t.Value).FirstOrDefault()

        'Rewrite Res2 example using the Take clause.
        'Res4 will be 0 because there is no "D" key
        Dim Res4 = (From t In myList Where t.Key = "D" Order By t.Value Descending Take 1 Select t.Value).SingleOrDefault()
    End Sub
End Module
But then I thought there has got to be a better way. How about calling the Max function directly and controlling what gets passed by using a Lambda expression?
Module Module3 'Calling Max directly with Lambda Expressions
    Private Structure test
        Public Key As String
        Public Value As Integer
    End Structure

    Sub Main()
        Dim myList As New List(Of test)
        myList.Add(New test() With {.Key = "A", .Value = 1})
        myList.Add(New test() With {.Key = "A", .Value = 2})
        myList.Add(New test() With {.Key = "A", .Value = 3})
        myList.Add(New test() With {.Key = "B", .Value = 1})
        myList.Add(New test() With {.Key = "B", .Value = 2})
        myList.Add(New test() With {.Key = "C", .Value = 1})

        'Create a blank list for testing
        Dim blankList As New List(Of test)

        'Res1 will be 0
        Dim Res1 = myList.Max(Function(p As test) If(p.Key = "D", p.Value, 0))

        'Res2 will error on empty list with "Sequence contains no elements"
        Dim Res2 = blankList.Max(Function(p As test) If(p.Key = "D", p.Value, 0))

        'Res3 will be nothing since list is blank and Lamda returns nullable integer type
        Dim Res3 = blankList.Max(Function(p As test) If(p.Key = "D", p.Value, New Integer?(0)))
    End Sub
End Module
But this still was kind of sticky if the function was called with an empty list. I noticed that the Max function is overloaded and can take a Nullable integer type. I created Res3 in the above example but then I thought about making a full circle back to where I started from. So here is my final example and what I based my fix on.
Module Module4 'Take 2 on Aggregate clause by forcing null values
    Private Structure test
        Public Key As String
        Public Value As Integer
    End Structure

    Sub Main()
        Dim myList As New List(Of test)
        myList.Add(New test() With {.Key = "A", .Value = 1})
        myList.Add(New test() With {.Key = "A", .Value = 2})
        myList.Add(New test() With {.Key = "A", .Value = 3})
        myList.Add(New test() With {.Key = "B", .Value = 1})
        myList.Add(New test() With {.Key = "B", .Value = 2})
        myList.Add(New test() With {.Key = "C", .Value = 1})

        'Create a blank list for testing
        Dim blankList As New List(Of test)

        'Res1 will be nothing since D does not exist and the overloaded
        '  Max function is called with a Nullable integer type.
        Dim Res1 = Aggregate t In myList Where t.Key = "D" Into Max(New Integer?(t.Value))

        'Same example but forcing the Integer Default value of 0
        'Res2 will be 0
        Dim Res2 = (Aggregate t In myList Where t.Key = "D" Into Max(New Integer?(t.Value))).GetValueOrDefault

        'And calling on an empty list works too!
        Dim Res3 = (Aggregate t In blankList Where t.Key = "D" Into Max(New Integer?(t.Value))).GetValueOrDefault


    End Sub
So as you can see, forcing the call to Max that processes the Null integer type looks to be the best answer.

Monday, August 11, 2008

A great use for extension methods

It seems like there is a lot of confusion out there about extensions methods. Some people say that it is bad programming practice to use them. I have also heard they were added solely to support LINQ and your average programmer should not have any use for them. Furthermore, why would you possibly want to add an Extension Method to your own custom class when you have the source code and could just add the method directly to the class?
Well, I think I have found the perfect use for Extension Method in tiered application development. I strongly believe in separating business objects, data access, logic, and UI development into distinct layers. And using Extension Methods allow greater ease in adhering to this approach. I will show you how it did for me.
First I want to briefly explain what an Extension Method is and then I will show an example of how I used extensions methods.

Extension Methods in a nutshell

An Extension Method is nothing more than a compile time feature. That is it. Nothing more! You don’t really get to magically add a method to any class that you choose nor get access to private members. When you create an Extension Method, you are simply registering a static method (or shared in VB) for the compiler to reference when it encounters that method name after an object variable reference. Here is an example of adding an Extension Method called print to a class named Contact:
    <Extension()> _
    Sub PrintLastName(ByRef contact As Contact)
        Console.WriteLine(contact.LastName)
    End Sub
In order to use this Extension Method I would need to make sure that my code imports the Name Space that the extension was defined in and the following code.
   Dim c As Contact = New Contact() With { _
       .FirstName = "John", _
       .LastName = "Smith", _
       .Phone = "214-844-1212"}

   'Call extension method
   c.PrintLastName()
However the call to the Extension Method PrintLastName is really being changed by the compiler to:
    PrintLastName(c)
That is it. It really is that simple. The compiler moves the object reference to the first parameter of the Extension Method call. If you don’t have the method in your imports section or in your current name space, you don’t see it, just like any other Sub. When you use the Extension Attribute, the Visual Studio IDE adds your Extension Method to Intelisence and makes it look it is part of the class. The actual class, Contact in this case, remains completely unchanged and unaware of this new Method.

My scenario and use of Extension Methods

For this example I have a solution with four projects, one for each layer. These are logical layers and the client application is deployed with a DLL from each project.
The first layer is for Business Objects and this layer’s only responsibility is to define what needs to be contained in the class. Nothing else! No database calls. No business Logic. Just a set of containers. Such as
Public Class Contact
    Private _contactId As Integer?
    Private _firstName As String
    Private _lastName As String
    Private _phone As String
    'Plus all the properties to expose these members.
End Class
The second layer is the data access layer. It is responsible for all of the loading and saving objects between the application and database. The client UI layer never touches the data access layer.
Public Class ContactDAL
    'CRUD methods
    Private Sub SelectContact(. . .

    Private Sub InsertContact(. . .

    Private Sub UpdateContact(. . .

    Private Sub DeleteContact(. . .
End Class
The third layer is the Facade. The client UI layer uses the layer exclusively and never calls into any of the other layers. It handles the generation of new objects, retrieving objects, saving objects, and all business logic.
Public Class ContactFacade
    Private Sub GetContact(. . .

    Private Sub SaveContact(. . .

    Private Sub CalculateSales(. . .
End Class 
And finally, the fourth layer is for the UI. The UI layer calls the Facade exclusively for all of it’s business objects needs.
In other tiered approaches it is very common to have the database layer intermingled with the business object layer. That gives you the nice abillilty to simply save an object by calling
   Contact.Save()
However in the BO/DAL/Facade layered approach before VS 2008, you would need to call the fa├žade methods to do your work. For example to save the contact object you would call
ContactFacade.SaveContact(c)
Not horrible but it sure is easier to just call c.Save isn’t it? Well you can with Extension Methods! If you have alread been using this same tiered programming approach, you most likely can just rename your methods and decorate them with the Extension Attribute to immediately be able to use this new functionality.
Function SaveContact(ByVal contact As Contact)
becomes
<Extension()> _
Sub Save(ByVal contact As Contact)
Of course this is assuming your Facade is defined as a module (or static class in C#). Now your UI layer can simply call c.Save()

Note on passing objects ByRef

I did discover a neat effect when working with Extension Methods. Usually a class’s method cannot destroy an object instance. However this can occur with Extension Methods! Some call this a bug, but I call it a feature and it produces the results I would expect.
    <Extension()> _
    Sub Delete(ByRef contact As Contact)
        'Only try to delete from database if object has Database Id
        If contact.ContactId.HasValue Then
            contactDao.DeleteContact(contact)
        End If

        contact = Nothing
    End Sub
Take note that in this example the contact parameter is ByRef. So calling c.Delete() from the UI layer results in c being set to nothing!

Consculsion

So there you have it. It is possible to maintain programming discipline that demands separating business objects and data access, but yet maintain ease of use, thanks to Extension Methods.

Friday, August 8, 2008

Custom TypeDescriptionProvider not being processed by Visual Studio Designer

While working with custom TypeDescriptionProvider's and setting TypeDescriptionProviderAttribute's on my classes, I found that my custom meta data was not being processed by the Visual Studio Datasources Window.

A single project had been created that contained both a Windows Form and my custom class files. This was just simply a test or "proof of concept" application so I just threw everything into one project. When I used the Data Sources window to add my class, Visual Studio was only showing the "real" properties of the class. This was in spite of the fact that I had decorated my class with the TypeDescriptionProviderAttribute pointing to my custom TypeDescriptionProvider that provided an extended list of properties. I knew the custom TypeDescriptionProvider was working correctly because I could create my data bindings in code.

I went to split up my single project into two differnt solutions so that I could debug the Visual Studio designer calls. I put the Window Form in one solution and my custom class and custom TypeDescriptionProvider in another solution. When I went to add my custom class to the Data Sources window of the Form solution, it came up correctly this time! Also, I tested the same with having one solution with two projects, and it still worked. So there must be a limitation or issue with having a TypeDescriptionProvider and attempting for the IDE to use it in the same project.

Conclusion, if you expect the Visual Studio IDE to process you Custom TypeDescriptionProvider, make sure those classes are in a separate project.

Thursday, August 7, 2008

AttributeCollection.Contains Method Can Return True on an Empty Collection

I found a weird side effect, or so I first thought, of the Contains method of the AttributeCollection class.

'desc references an instance of my custom type derived from the PropertyDescriptor class
'desc.Attriutes is an EMPTY collection
dim x as boolean = desc.Attributes.Contains(New BrowsableAttribute(true))

Since desc.Attributes is an empty collection, calling the Contains method with any value couldn't possibly return anything but false, right?!?!? But as it turns out, the above statement will return True. This seemed absolutely crazy to me at first. But then I called:

'This time BrowsableAttribute is set false.
dim x as boolean = desc.Attributes.Contains(New BrowsableAttribute(false))

In this case x was set to False.

So my conclusion is that there must be some extra logic in the AttributeCollection.Contains method. It is not just your typical contains method that is just simply looking for an object match. It is smarter than that!

Since the BrowsableAttribute default is True, asking if the Attributes collection contains a default attribute value is in fact really true even when the Attributes collection is empty, or for that matter contains other attributes.

Now that I understand this, I am confident that this was the intended behavior of the Contains method. And if you really want to see if an Attribute is specified in the collection, regardless of its default setting, use the AttributeCollection.Matches method instead.

Sunday, August 3, 2008

Custom Markup Extensions in WPF

Since I have been working with Windows Presentation Foundation, I have been looking for a good reason to make my own custom markup extension. What follows is the problem that I wanted to solve, a brief overview of markup extensions and how I implemented my solution.
Problem to be solved
Every ListBox and ComboBox needs a list of options and nothing is more irritating to me than seeing a long list of options directly hard-coded into an application. Therefore, pretty much every project that I have worked on, there has been a need to create a database table to manage selection options.
Typically such a table has been named ListOptions, ControlData, Keywords or something similar and has had columns for the key, display text, value, and display order. So for example, to populate a Comb Box of name prefixes, such as Mr., Mrs., Dr., etc, a simple query to filter the key on NameSuffix is used to build the list.
As you can imagine this is only used for adhoc scenarios where the values do not have a supporting relational table and it is desirable to store a value versus a database key. Obviously if I wanted to store for example a sales person associated to an order, that would be a relational join to a SalesPerson table and the control would be bound to that table for a list of sales persons.
Here is example code that simulates the look-up table, which will be referenced later. Of course the real code would create the ListOption objects from data in the database table.
'This example uses the Linq so be sure to reference and import System.Data.Linq

Module ListOptions
    'This example creates the data array in code.  In a real app this would be a
    'database query in place of this code.

    Private _options As ListOption() = { _
        New ListOption With {.Key = "ShirtColor", .Display = "Red"}, _
        New ListOption With {.Key = "ShirtColor", .Display = "Green"}, _
        New ListOption With {.Key = "ShirtColor", .Display = "Blue"}, _
        New ListOption With {.Key = "ShirtSize", .Display = "Small"}, _
        New ListOption With {.Key = "ShirtSize", .Display = "Medium"}, _
        New ListOption With {.Key = "ShirtSize", .Display = "Large"}, _
        New ListOption With {.Key = "NamePrefix", .Display = "Mr."}, _
        New ListOption With {.Key = "NamePrefix", .Display = "Mrs."}, _
        New ListOption With {.Key = "NamePrefix", .Display = "Ms."}, _
        New ListOption With {.Key = "NameSuffix", .Display = "Jr."}, _
        New ListOption With {.Key = "NameSuffix", .Display = "Sr."} _
        }

    Function GetOptions(ByVal key As String) As List(Of ListOption)
        'Do a simple LINQ expression to return all ListOption objects that match
        'the specified key
        Return (From lo In _options Where lo.Key = key Select lo).ToList
    End Function
End Module
'Class to represent ListOption Table Row
Public Class ListOption
    Private _key As String
    Public Property Key() As String
        Get
            Return _key
        End Get
        Set(ByVal value As String)
            _key = value
        End Set
    End Property

    Private _display As String
    Public Property Display() As String
        Get
            Return _display
        End Get
        Set(ByVal value As String)
            _display = value
        End Set
    End Property

    '...
    'Also would need value member, display order, etc.
End Class
Typical Solutions
In WPF there are two immediate solutions that might come to mind for most developers to bind the options to a control's ItemsSource property.
The first thought might be adding an ObjectDataProvider to call a method in your class that returns a list.
<window class="Window1" title="Window1" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" width="300" local="clr-namespace:WpfApp1" height="300" x="http://schemas.microsoft.com/winfx/2006/xaml">
     <window.resources>
          <objectdataprovider methodname="GetListOptions" objecttype="{x:Type local:ListOptions}" key="ColorOptions">
               <objectdataprovider.methodparameters>
                    NamePrefix
               </objectdataprovider.methodparameters>
          </objectdataprovider>
     </window.resources>
     <grid>
          <listbox name="MyListBox" height="80" displaymemberpath="Display" itemssource="{Binding Source={StaticResource ColorOptions}}">
     </grid>
</window>
The other solution might be to set the DataContext in the load event.
Class Window1
     Private Sub Window1_Loaded(ByVal sender As System.Object, ByVal e As System.Windows.RoutedEventArgs) Handles MyBase.Loaded
          MyListBox.ItemsSource = GetListOptions("NamePrefix")
     End Sub
End Class
But what about a simpler and more extensible solution? What if you could just simply make a reference in the ItemsSource property to initiate and return the lookup? The solution: a custom Markup Extension.
Markup Extension Overview
Markup Extensions are a key part of WPF and when first learning WPF it may not even be obvious of what one is or the fact that you can create you own.
So what is a Markup Extensions? Here is a short except from the .Net Online help under the topic "XAML Overview"
Markup extensions are a XAML concept. In attribute syntax, curly braces ({ and }) indicate a markup extension usage. This usage directs the XAML processing to escape from the general treatment of attribute values as either a literal string or a directly string-convertible value.
Here are a few examples
{x:Static ...}
{x:Type ...}
{StaticResource ...}
The very first part of a Markup Extension expression after the opening brace references the class to call. You might be thinking there is no class called "Static" in the .Net Framework. And you are right there isn't. This is because Markup extensions are assumed to have the suffix of "Extension". So now that you know this you can go look in the online help and find StaticExtension, TypeExtension, and StaticResourceExtension, which are all perfectly defined.
So now that you know that the first keyword is a class reference, let's go create our very own "Hello World" Markup Extension called MyTestExtension.
Besides our class name needing to end with "Extension" there is one other important requirement to take note of. Our class will need to inherit from MarkupExtensionBase and override the ProvideValue function.
Public Class HelloWorldExtension
    Inherits Markup.MarkupExtension

    'This method is called by the XAML processor.
    Public Overrides Function ProvideValue(ByVal serviceProvider As System.IServiceProvider) As Object
        Return "Hello World!"
    End Function
End Class
And the XAML code that uses a TextBox to display the results.
<Window x:Class="Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:WpfApp1"
    Title="Window1" Height="300" Width="300" Name="Window1">
     <Grid>
        <TextBox Text="{local:HelloWorld}" VerticalAlignment="Bottom" Height="20" />
    </Grid>
</Window>
Let's now take a look at the other part of a markup extension expression. Either the class's proprieties are set using the X=VALUE method, or values are simply listed in order of the class's New constructor.
For example, the StaticResource class can be called either of the following ways:
{StaticResource MyKey}
{StaticResource ResourceKey=MyKey}
The first line calls the New constructor with the value specified. The second line creates a new StaticResourceExtension object and then sets the ResourceKey property to the specified value. Either way should always result in the same return provided by the ProvideValue function.
Here is an example of our new MyTestExtension class, now a little more versitle by using a parameter.
Public Class HelloWorldExtension
    Inherits Markup.MarkupExtension


    Private _name As String
    Public Property Name() As String
        Get
            Return _name
        End Get
        Set(ByVal value As String)
            _name = value
        End Set
    End Property

    'Default Constructor
    Public Sub New()

    End Sub

    'Constructor to set name property
    Public Sub New(ByVal name As String)
        _name = name
    End Sub

    'This method is called by the XAML processor.
    Public Overrides Function ProvideValue(ByVal serviceProvider As System.IServiceProvider) As Object
        Return "Hello World! From " & _name
    End Function
End Class
And the XAML code that uses a TextBox to display the results using either method.
<Window x:Class="Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:WpfApp1"
    Title="Window1" Height="300" Width="300" Name="Window1">
     <Grid>
        <TextBox Text="{local:HelloWorld John}" VerticalAlignment="Top" Height="20" />
        <TextBox Text="{local:HelloWorld Name=John}" VerticalAlignment="Bottom" Height="20" />
    </Grid>
</Window>
If you are doing this with the split Designer/Code view in Visual Studio 2008 you should be noticing that the results from the HelloWorldExtension class are displayed in the designer pane. Pretty cool, huh?
The solution
Now for the solution originally promised.
<Markup.MarkupExtensionReturnType(GetType(List(Of ListOption)))> _
Public Class ListOptsExtension
    Inherits Markup.MarkupExtension

    'Define our member and property for the Key
    Private _key As String
    Public Property Key() As String
        Get
            Return _key
        End Get
        Set(ByVal value As String)
            _key = value
        End Set
    End Property

    'Default Constructor
    Public Sub New()
    End Sub

    'Constructor with key specified as parameter
    Public Sub New(ByVal key As String)
        _key = key
    End Sub

    'This method is called by the XAML processor.
    Public Overrides Function ProvideValue(ByVal serviceProvider As System.IServiceProvider) As Object
        Return GetListOptions(_key)
    End Function
End Class
And now the grand finale. Look how easy it is to set the ItemsSources property with options loaded from a table!
<window class="Window1" title="Window1" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" name="Window1" width="300" local="clr-namespace:WpfApp1" height="300" x="http://schemas.microsoft.com/winfx/2006/xaml">
<grid>
<listbox name="MyListBox" height="80" displaymemberpath="Display" itemssource="{local:ListOpts NamePrefix}">
</grid>
</window>
Now with just a few keystrokes in our XAML code, we can easily fill every ComboBox or ListBox we have in our application. I love WPF and how extensible it is!
Extra Notes
Here is an important side note regarding ListBoxes and ComboBoxes. A typical application will probably be required to bind the selection of the ListBox or ComboBox control to a business object. In this example, if the SelectedValuePath property of the ListBox control was not specified, binding the SelectedValue property would reference the ListOption object instead of the string value that should be referenced. With the SelectedValuePath property specified, the binding between SelectedValue and a business object's string property will link up perfectly.
Taking Markup Extensions Further
I have also created markup extensions for places where I need a computed value, such as the currently logged in user. So Markup Extensions are also very comparable to macro capabilities found in other markup language languages.