WCF 3.5: UriTemplateTable

22. August 2007 06:23

In some previous posts, I highlighted some of the major functionality for UriTemplate and UriTemplateMatch.  Before I move on to the new functionality that really begins to consume these building blocks, it only seemed fair to also point out another useful new class related to working with uris.  As you could probably judge by the title of the post, I am referring to the UriTemplateTable.

So, what exactly does UriTemplateTable do for you?  You can essentially think of it as UriTemplateMatch on steroids.  The name really gives it away.  The UriTemplateTable provides support for storing a set of related UriTemplates.  A candidate uri can be run against the UriTemplate objects within the table to determine the most appropriate match or matches. 

Let's look at some code to clarify what I am talking about.  Here is an example using Keith Elder's Flickr archive.

// Setup a template table for the base address.
UriTemplateTable table = new UriTemplateTable(new Uri("http://www.flickr.com/photos/keithelder/archives"));

// Add the templates to the table.
table.KeyValuePairs.Add(
    new KeyValuePair<UriTemplate, object>(
    new UriTemplate("{takenOrPosted}/{year}/calendar/"),
    "some info about the template"));

table.KeyValuePairs.Add(
    new KeyValuePair<UriTemplate, object>(
    new UriTemplate("takenOrPosted}/{year}/{month}/calendar/"),
    "more info about the template"));

table.KeyValuePairs.Add(
    new KeyValuePair<UriTemplate, object>(
    new UriTemplate("takenOrPosted}/{year}/{month}/{day}/"),
    "yet even more info about the template"));

So far, all we have done is setup a UriTemplateTable that contains a set of related UriTemplates.  If you look closely, you can see there are some similarities between the UriTemplates.  Each one adds an extra level of detail to the possible date.  This could have been taken a step further and the user made into a parameter as well, but we are keeping this example specific to Zorka. :)

You may be wondering what is this KeyValuePair business all about?  This is one of the other nice features in UriTemplateTable.  The UriTemplates are stored as an ILIst of KeyValuePairs.  The key is the UriTemplate and the value is an object of your choosing.  Unfortunately, you are forced to use the Object type rather than supplying a type parameter.  Regardless, this could potentially be quite useful.  You can essentially store any information that you deem to be relevant with each instance of UriTemplate. 

Now that a UriTemplateTable is setup with our UriTemplates, it's time to unleash its matching capabilities.

// Create a candidate uri for a match.
Uri candidateUri = new Uri("http://www.flickr.com/photos/keithelder/archives/date-posted/2007/01/calendar/");

// Tell the table to match against the uri.
Collection<UriTemplateMatch> matchResults = table.Match(candidateUri);

// Check if a match was found.
if ((matchResults != null) && (matchResults.Count > 0))
{
    // Write out each result.
    foreach (UriTemplateMatch match in matchResults)
    {
        Console.WriteLine();
        Console.WriteLine("Template: " + match.Template.ToString());
        Console.WriteLine("Parameters");

        foreach (string key in match.BoundVariables.Keys)
        {
            Console.WriteLine("   Name: {0} | Value: {1}", key, match.BoundVariables[key]);
        }
    }
}

Output:

Template: {takenOrPosted}/{year}/{month}/calendar/
Parameters
   Name: TAKENORPOSTED | Value: date-posted
   Name: YEAR | Value: 2007
   Name: MONTH | Value: 01

Notice the Match method returns a Collection of UriTemplateMatch objects.  This is a result of the possibility that more than one template could match against the candidate uri.  It may be necessary to do some additional work to narrow down your results, but it's better than the alternative of manually writing the code to support this behavior.  There is also a MatchSingle method that will attempt to return only one match.  However, it will result in a UriTemplateMatchException if more than one match is found.  So, proceed with caution.

As a final note, there is another method that I haven't included in the sample code named MakeReadOnly.  As the name suggests, it prevents any additional changes from being made to the UriTemplateTable when true is passed as a parameter.  However, an exception will be thrown if you pass true and the UriTemplateTable contains more than one UriTemplate that is structurally equivalent. 

In the next WCF 3.5 post, I will begin getting into how these new Uri support classes are leveraged by WCF's new features.

Comments

8/21/2007 7:57:57 PM #

Very funny Mr. Barnes.  I shall retaliate in kindness.

Keith Elder |

8/22/2007 3:56:07 PM #

Well, I would have just done a generic Flickr example since their uri structure was a good fit, but it makes things more interesting to use a specific context. Smile

jeff.barnes |

10/15/2007 12:31:07 PM #

http://

Hi Jeff,
I just tried compiling and running this sample under Beta 2, but I cant seem to get the table to match.  Here's the code: Any ideas?

static void Main(string[] args)
        {
            // Setup a template table for the base address.
            UriTemplateTable table = new UriTemplateTable(new Uri("http://www.flickr.com/photos/keithelder/archives"));

            // Add the templates to the table.
            table.KeyValuePairs.Add(
                new KeyValuePair(
                new UriTemplate("{takenOrPosted}/{year}/calendar/"),
                "some info about the template"));

            table.KeyValuePairs.Add(
                new KeyValuePair(
                new UriTemplate("takenOrPosted}/{year}/{month}/calendar/"),
                "more info about the template"));

            table.KeyValuePairs.Add(
                new KeyValuePair(
                new UriTemplate("takenOrPosted}/{year}/{month}/{day}/"),
                "yet even more info about the template"));
            
            // Create a candidate uri for a match.
            Uri candidateUri = new Uri("http://www.flickr.com/photos/keithelder/archives/date-posted/2007/01/calendar/");

            // Tell the table to match against the uri.
            Collection matchResults = table.Match(candidateUri);

            // Check if a match was found.
            if ((matchResults != null) && (matchResults.Count > 0))
            {
                // Write out each result.
                foreach (UriTemplateMatch match in matchResults)
                {
                    Console.WriteLine();
                    Console.WriteLine("Template: " + match.Template.ToString());
                    Console.WriteLine("Parameters");

                    foreach (string key in match.BoundVariables.Keys)
                    {
                        Console.WriteLine("   Name: {0} | Value: {1}", key, match.BoundVariables[key]);
                    }
                }
            }

            Console.ReadLine();
        }

http:// |

10/17/2007 3:30:04 PM #

http://

Matt,

Take a look at the following file: jeffbarnes.net/.../WhatsNewInWCF35.zip.  This contains the demos that I used for my latest Alabama Code Camp presentation.  It contains code that is very similar to the sample in this post.

http:// |

Comments are closed

About Me

I'm a passionate software developer and advocate of the Microsoft .NET platform.  In my opinion, software development is a craft that necessitates a conscious effort to continually improve your skills rather than falling into the trap of complacency.  I was also awarded as a Microsoft MVP in Connected Systems in 2008, 2009, and 2010.


Can’t code withoutThe best C# & VB.NET refactoring plugin for Visual Studio
Follow jeff_barnes on Twitter

View Jeff Barnes's profile on LinkedIn

 

Shared Items

Disclaimer

Anything you read or see on this site is solely based on my own thoughts.  The material on this site does not necessarily reflect the views of my employer or anyone else.  In other words, I don't speak for anyone other than myself.  So, don't assume I am the official spokesperson for anyone.