REST in WCF – Part IX – Controlling the URI

(click here for an index of the complete series, as well as supporting screencasts)

(click here for a screencast illustrating "Controlling the URI")

Resources in REST

Arguably, the most fundamental concept in REST is that of a resource.  It is best to think of it as a conceptual representation of an entity or entities.  Blah, blah, blah, conceptual, blah blah blah, representation, blah, blah, blah entity.  What does all of that mean anyway?  Think of it this way, if you can create a link to it, it is a resource.  Now what does conceptual representation mean?  Essentially, it means that the resource is an abstraction.  It is not the underlying entity itself, rather a mapping to that entity… and that mapping may change.  Whoa, the mapping may change?  How is that?  Consider the example that you wanted to expose the top 10 best selling books at your online store.  The resource would be those top 10 best selling books.  It is clear that those would change over time. 

The need for the abstraction should be clear.  In our previous example, we don’t really care what the back end was  that stored the top 10 best selling books.  It was, more than likely, a database system.  It could have been Microsoft Sql Server, or it could have been Oracle or Informix or something altogether different.  We don’t really care because we are not interested in the entity itself, rather the representation.  If we were to switch back ends out after a period of time, it would be meaningless to us.  The representation would be unaffected (although, as we argued earlier the representation might have changed).  Further, imagine the complexity of the system where we were not mapping to the concept, but to the actual underlying entities. 

URIs in REST

The way in which you identify a resource is through a URI.  Section 6.2.1 of Fielding’s dissertation points out that "The definition of resource in REST is based on a simple premise: identifiers should change as infrequently as possible."  He further states that "authors need an identifier that closely matches the semantics they intend by a hypermedia reference…"  This points out the importance of the structure of the URI.  Many folks try to create what I refer to as "Hackable" URIs.  These are URIs that are easily remembered and whose structure and semantics are clear enough to manipulate.  Take for instance the following URI: ‘http://www.someuri.com/Product/Flange’.  It is pretty clear the the structure is: the http scheme and the hostname (‘http://www.someuri.com’) followed by 2 segments: Product and ProductName.  A template for this might look like the following:  ‘http://www.someuri.com/Product/{ProductName}’ where {ProductName} represents a variable.

You might argue that this is bad design, in that if the name of the product changes, so must the URI and that clearly violates the premise that a resource is based on.  Another approach would be to use the ProductID as the final segment.  I’ll leave that up to you.  What I want to discuss in this post is what your options are for controlling the URI, assuming you have already designed how the URI should look.

The approach of this Post

If you have ever seen ‘What About Bob’ with Bill Murray, you will understand the following reference (if you haven’t, close your notebook, go to Blockbuster, rent ‘What About Bob’, come home, put it in the DVD player, open a beer – if that is your thang – and watch it).  We are going to take baby steps to controlling the URI.  I am going to start by outlining the default URI behavior when using the webHttpBinding along with the webHttp endpoint behavior.  I will then show you what your options were in manipulating the URI structure via the UriTemplate.  I’ll then move on to some additional functionality available in SP1.  Lastly, I’ll illustrate how you can take complete control over the structure of the URI using IIS7 and the Url Rewrite Module.

The Sample

Below you will see the service contract and operation contract of our sample service.  As you can see, the operation is named GetWine and takes in a string of wineID.  You will also note that I have decorated the operation contract with a WebGetAttribute, making this callable via an HTTP GET.  I have omitted the implementation, as well as the configuration, as they adds no value to this discussion.

[ServiceContract]
public interface IRESTWineService
{
    [OperationContract]
    [WebGet(ResponseFormat = WebMessageFormat.Xml)]
    WineData GetWine(string wineID);
}

One other point to make is that address to this web is http://localhost/RESTControllingUri.

The Default Behavior

It may not be clear, but this operation does have a unique URI associated with it.  The default URI scheme is the path to the *.svc file, followed by a segment with the operation name, followed by querystring parameters for each operation argument.  The following represents the default structure of the URI:

[protocol]://[hostname][:port][/path][/svc filename][?argument1=value1[&argument2=value2 …]]

In the case of our example, it looks like this:

The UriTemplate

When we released the webHttpBinding and the webHttp endpoint behavior in WCF 3.5, we provided the ability to define a UriTemplate.  Aptly named, the UriTemplate allows you to define a template for a set of URIs that follow a similar structure or pattern.  The UriTemplate has 2 parts: the path and the query.  The path is a series of segments.  The segments can contain literals, parameters or variables and wildcards.  Here are some examples:

  • literal:  /products
  • literal:  /products/sportinggoods
  • literal and variable:  /product/{productId}  (Where productId is a parameter that is mapped to an operation argument)
  • wildcard:  /products/*

The query contains name-value pairs that represent the querystring parameters collection.  Here are some examples: 

  • literal in query:  /products?type=json
  • variable in query:  /products?index={index}&pageSize={pageSize}

You can set a UriTemplate through code or you can pass it as a parameter to a WebGetAttribute or WebInvokeAttribute.  Here is an example of the latter:

[OperationContract]
[WebGet(UriTemplate="/products?index={index}&pageSize=
    {pageSize}")]
WineData GetProducts(int index, int pageSize);

* One important thing to note.  In the current release (SP1), if your variables are part of the query, such as above, we will do simple type conversions for you.  So, in the previous example, note that GetProducts takes in integers, but clearly the querystring parameters are strings.  We will take care of this simple conversion for you.  However, if the variables are in the path, we will not.  There is no reason for this, other than it was done for the query, not the path.  It is my understanding that support for type conversions in the path is on the list for a future release.  Just thought you might like to know.

As you can see, the UriTemplate is useful in controlling the URI.  However, there are limitations.  As my might have noticed, the template is defined for the path and querystring after the path to the svc file.  It does not provide any help for manipulating that portion of the URI.

(see this article on MSDN for more information on UriTemplates)

Given this information, we could define a UriTemplate to clean up the URI for our GetWine operation.  Perhaps we want the path to be something like this:  wine/17 (where 17 is an actual wine id).  We could simply change our code to look like this:

[OperationContract]
[WebGet(UriTemplate="wine/{wineID}",
        ResponseFormat = WebMessageFormat.Xml)]
WineData GetWine(string wineID);

The call would look like this:

UriTemplate Enhancements in WCF 3.5 SP1

The WCF team added some enhancements to UriTemplates when Visual Studio 2008 SP1 (and Fx 3.5 SP1) was released.  These included support for default values for parameters in paths and compound template segments.  It is simple to define a default value.  Simply set the variable to the default value with an ‘=’.  Remember that you cannot assign defaults to variables in the query portion of the template.  Here is what our example would look like, setting the default value of wineID = 22:

[OperationContract]
[WebGet(UriTemplate="wine/{wineID=22}",
        ResponseFormat = WebMessageFormat.Xml)]
WineData GetWine(string wineID);

You can now omit the id segment of the URI like this:

Compound template segments allow you to combine both variables and literals within one segment.  If you are familiar with ADO.NET Data Services, you will note that the ID for entities uses compound template segments.  The IDs look like this:  Entity(id).  ADO.NET Data Services runs on WCF and the webHttpBinding, so you might rightly assume that this functionality was added for this purpose.  However, you can take advantage as well.  If I wanted to implement a similar ID scheme, it would look like this:

[OperationContract]
[WebGet(UriTemplate="wine({wineID})", ResponseFormat =
        WebMessageFormat.Xml)]
WineData GetWine(string wineID);

Here is what it looks like:

Completely Controlling the URI

All of the examples we have seen so far only allow us to template the URI after the path to the svc file.  If you want to take full control of the URI, you have to do some kind of URL Rewriting.  There are a variety of means to accomplish this.  ScottGu’s blog post Tip/Trick: Url Rewriting with ASP.NET illustrates 4 approaches, including implementing HttpModules, using Request.PathInfo and taking advantage of 3rd party ISAPI filters.  John Flanders’ blog post Using WCF WebHttpBinding and WebGet with nicer Urls illustrates how you can build an HttpModule with IIS7 for URL Rewriting.  In this post, I will illustrate how you can take advantage of the new URL Rewrite Module for IIS 7.0 CTP1.  This module allows you to simply add rules that define pattern matches (either Regular Expressions or WildCards) and rewrite to a specified URL pattern.  Actually the module does more than that.  To see the full functionality, check out Bill Staples’ blog post on the subject.

For our purposes, we simply want to define a pattern for the incoming URL using Regular Expressions.  This pattern will represent what we want the "Hackable" URI to look like.  We will then take this URI and rewrite it to the actual path that we defined earlier ([protocol]://[hostname][:port][/path][/svc filename]).  An example will probably best illustrate our goal and how we can accomplish it.  Taking the last example we had, the URI looked like this:

As my annotations clearly point out, we may not want the ".svc" as part of our URI.  That is really a technical implementation detail and does not really have a place in the "hackable" URI.  So, for this simple example I will illustrate how we can use the Url Rewrite Module to remove the svc extension.  Here is the process:

  1. Make sure you have installed Vista SP1
  2. Make sure you have installed the CTP of the Rewrite Module
  3. Open IIS 7
  4. Navigate to your application and dbl-click on the URL Rewrite Module Icon
  5. Click on add rule in the upper right hand corner
  6. Fill out the form with the following data (we will describe the patterns in detail in a moment):
    1. Name:                       Remove Svc Extension (or any name you want)
    2. Requested URL:         Matches the pattern
    3. Using:                       Regular Expressions
    4. Pattern:                    ^([0-9a-zA-Z\-]+)/([0-9a-zA-Z\-\.\/\(\)]+)
    5. Ignore Case:             Checked
    6. Action Type:              Rewrite
    7. Rewrite URL:             {R:1}.svc/{R:2}
    8. Append QueryString   Checked
  7. Click Apply

You are ready to go.  But before we test it, I want to dissect the pattern we used for matching.  The match pattern was:

^([0-9a-zA-Z\-]+)/([0-9a-zA-Z\-\.\/\(\)]+)

Here is the breakdown of the pattern:

  • The "^" indicates the beginning of the line or string
  • The parenthesis "()" allow you to define a numbered capture group, meaning that you can reference everything inside the parens later by index.  In our example, we have 2 numbered capture groups 1 and 2.  You refer back to these later with the syntax: {R:1} and {R:2}
  • The pattern [0-9a-zA-Z\-]+ indicates any character in 0-9, lowercase a-z, uppercase A-Z or "-", one or more repetitions.
  • The / is a straight match to a slash "/".  In other words, the first named capture group will capture 0-9,a-z, A-Z and "-" prior to the first "/" and you will be able to reference them with {R:1}
  • Then we have another named capture group
  • The pattern [0-9a-zA-Z\-\.\/\(\)] matches any character in 0-9, lowercase a-z, uppercase A-Z or "-", ".", "/", "(", ")", one or more repetitions.

The rewrite URL is simply everything in the first named capture group (everything prior to the first /) which should be the svc file, without the svc extension.  We then append an svc extension and a slash.  We then append everything in the named capture group. 

Let’s see it in action.  Here is our new svc-less request:

Eliminating the ".svc" extension is just the tip of the iceburg.  Hopefully, you can see how you can take full control of the URI.

“Oslo” Interviews on Channel 9

As you know “Oslo” is the family of new technologies that enable data-driven development and execution of services and applications.  There will be several sessions at PDC discussing the technologies involved in “Oslo” in much detail.  In the interim, we have published two interviews on Channel 9. 


 


In these interviews, our very own Ron Jacobs talks to David Chappell and Jon Flanders to understand their perspectives on “Oslo” and how we can prepare for the road ahead.  If you’re wondering about “Oslo” tools, language and repository and want to build your apps today to prepare for the road ahead, you’d then definitely want to watch these videos.


 


Enjoy!


Marjan Kalantar

Failed to Serialize the Message Part, Ensure that the Message Part Stream is Created Properly

Encountered the following error today on a SOAP [Send] Port:
Failed to serialize the message part “[PART NAME]” into the type “[MESSAGE TYPE]” using namespace “[NAMESPACE]“. Please ensure that the message part stream is created properly.
The error is a little misleading, especially ‘ensure that the message part stream is created properly‘ – the message part stream […]

Can Microsoft + Seinfeld outdo Apple’s marketing?

Can Microsoft + Seinfeld outdo Apple’s marketing?

Mary Jo Foley reported about this yesterday and now it's all over the news. Microsoft is gearing up to launch a $300M advertising campaign to combat the negative ads launched against them in recent years, and to rebuild the company's fading image. Since the "Get a Mac" ad campaign first started, and proved sooo effective, I've been dumbfounded by the fact that Microsoft has just sat back and taken it, one hit at a time. I even started to wonder if Microsoft would ever launch a counter strike.  I finally started to conclude that maybe Microsoft isn't actually able to orchestrate a successful counter-campaign given their historic lack of creativity with all things marketing, and maybe it was better that way. Because if they actually tried to do something, and it flopped, that would make things even worse for the company.

Well, it looks like the day has finally arrived like it or not.

The key question was always…who would they use as spokesperson? Given the Mac ads, they really need just the right guy to pull it off and resonate. Well, they've chosen Jerry Seinfeld for the spokesperson role (he gets $10M), which made me really happy when I first heard about it.

Since then, however, I've been poking around to see what others are saying, and many are questioning if he's the right choice. Some say he's out-of-date. Some point to his ineffective AMEX commercials. And some say the biggest problem with Jerry is that he actually seems more like a Mac Guy. In fact, didn't Jerry have a Mac in his Seinfeld set apartment all those years? Apparently, some Microsoft partners aren't completely convinced either.

Despite Microsoft's latest attempts to improve Vista perception via The Mojave Experiment, there are some who believe that Microsoft's fundamental problem isn't lack of marketing but rather a flawed product (Vista) and that they should spend the $300M fixing that first. Some say this is just a pathetic attempt by Gates to get back at Jobs (apparently the Mac ads really ticked him off). Who knows.

I personally believe that Microsoft's move to get more aggressive with their marketing is the right call. There's simply too much negativity targeting them to withstand it sitting still. While some of the negativity may be merited, a lot of it clearly isn't, and perception is king. And I'm glad to hear that they're taking this seriously — a $300M campaign is significant — they need to do it right. Now they just need to nail the creative.

It will be very interesting, and hopefully entertaining, to watch these new ads roll out combined with the celebrity of Jerry Seinfeld.

I sure hope it works…Microsoft needs a win here.

Thanks Lutz Roeder!

Thanks Lutz Roeder!

Lutz Roeder, creator of the ever-so-popular .NET Reflector, sent out the following email today announcing a big change for his tool:

After more than eight years of working on .NET Reflector, I have decided it is time to move on and explore some new opportunities.

I have reached an agreement to have Red Gate Software continue the development of .NET Reflector. Red Gate has a lot of experience creating development tools for both .NET and SQL Server. They have the resources necessary to work on new features, and Reflector fits nicely with other .NET tools the company offers.

Red Gate will continue to provide the free community version and is looking for your feedback and ideas for future versions.

For news and updates on Reflector, sign up for the .NET Developer’s Newsletter from Red Gate. To find out more about the agreement, see the interview on Simple Talk.

I've personally used .NET Reflector extensively over the years, ever since its earliest release, and it has never let me down. It's come to my rescue on many occasions as I've struggled to understand different areas of the .NET Framework. My experience wouldn't have been the same without it.

So I guess I just wanted to say…thanks Lutz! 

And best of luck to Reg Gate in continuing his great work.

Module window not available

If you are debugging pipelines or adapters in BizTalk, you can’t just ‘debug’ the said component in Visual Studio (however, there are rumors of that changing in v.Next), you have to deploy and run it in the service.

You need to attach to the BTSNTSvc.exe and if you are lucky, all of the pdb files are in the correct place, and you can instantly start debugging.

However, if you are like me, and the dlls are in separate locations from the pdb files (GAC for example), you need to associate the dll with the pdb. This can only be done via the Module window.

According to the Module Window definition on MSDN you should “On the Debug menu, choose Windows, and then click Modules.”

However, this is what I see:

The easiest you can bring it up is by pressing Ctrl – Alt – U