Skip to content

Url Form Encoded Formatter Overview

mikeobrien edited this page Sep 14, 2010 · 2 revisions

The form url encoded formatter will serialize and deserialize form url encoded values. Parameter names are made up of the full path in the object graph delimited by a period. Items in a collection will be suffixed with pound sign and the numerical index of the item, starting with the second item.

The form url encoded formatter can be configured declaratively on the service with the WcfRestContrib.ServiceModel.Description.WebDispatchFormatterConfigurationAttribute and WebDispatchFormatterMimeTypeAttribute:

[WebDispatchFormatterConfiguration("application/x-www-form-urlencoded")]
[WebDispatchFormatterMimeType(
    typeof(WcfRestContrib.ServiceModel.Dispatcher.Formatters.FormUrlEncoded),
    "application/x-www-form-urlencoded")]
public class Books : IBooksService {...}

Or in configuration:

<system.serviceModel>
    <extensions>
        <behaviorExtensions>
            <add name="webFormatter" 
                 type="WcfRestContrib.ServiceModel.Configuration.WebDispatchFormatter.ConfigurationBehaviorElement, WcfRestContrib, 
                       Version=x.x.x.x, Culture=neutral, PublicKeyToken=89183999a8dc93b5"/>
        </behaviorExtensions>
    </extensions>
    <serviceBehaviors>
        <behavior name="Rest">
          <webFormatter>
            <formatters defaultMimeType="application/x-www-form-urlencoded">
              <formatter mimeTypes="application/x-www-form-urlencoded" 
                         type="WcfRestContrib.ServiceModel.Dispatcher.Formatters.FormUrlEncoded, WcfRestContrib"/>
            </formatters>
          </webFormatter>
        </behavior>
    </serviceBehaviors>
</system.serviceModel>

One or more formatters can be defined.

Lets take a look at a few examples. The following data contract:

[DataContract]
public class Book
{
    [DataMember]
    public string Title { get; set; }

    [DataMember]
    public string Author { get; set; }

    [DataMember]
    public int Published { get; set; }
}

Book book = new Book() {
    Title = "Night Thoughts of a Classical Physicist",
    Author = "Russell McCormmach",
    Published = 1991 };

Will serialize as follows:

Book.Title=Night+Thoughts+of+a+Classical+Physicist&Book.Author=Russell+McCormmach&Book.Published=1991

If we change the contract to include a list:

[DataContract]
public class Book
{
    [DataMember]
    public string Title { get; set; }

    [DataMember]
    public Authors Authors { get; set; }

    [DataMember]
    public int Published { get; set; }
}

[CollectionDataContract(ItemName="Author")]
public class Authors : List<string> { }

Book book = new Book() {
    Title = "Expert F#",
    Authors = new Authors()
        {
            {"Don Syme"},
            {"Adam Granicz"},
            {"Antonio Cisternino"}
        },
    Published = 2007 };

It will serialize as follows (Carriage return added for readability):

Book.Title=Expert+F#&Book.Authors.Author=Don+Syme&Book.Authors.Author#2=Adam+Granicz&
Book.Authors.Author#3=Antonio+Cisternino&Book.Published=2007

Posting the above information in an html form as follows:

<form action="http://services.mylibrary.com/books" method="POST">
Title: <input type="text" name="Book.Title" /><br/>
Author 1: <input type="text" name="Book.Authors.Author" /><br/>
Author 2: <input type="text" name="Book.Authors.Author#2" /><br/>
Author 3: <input type="text" name="Book.Authors.Author#3" /><br/>
Published (Year): <input type="text" name="Book.Published" /><br/>
<input type="submit" />
</form>

If the authors list contained a more complex type:

[DataContract]
public class Book
{
    [DataMember]
    public string Title { get; set; }

    [DataMember]
    public Authors Authors { get; set; }

    [DataMember]
    public int Published { get; set; }
}

[DataContract]
public class Author
{
    [DataMember]
    public string Name { get; set; }

    [DataMember]
    public string PenName { get; set; }
}

[CollectionDataContract(ItemName="Author")]
public class Authors : List<Author> { }

Book book = new Book() {
    Title = "Expert F#",
    Authors = new Authors()
        {
            new Author() { Name = "Don Syme", PenName = "Rocky" },
            new Author() { Name = "Adam Granicz", PenName = "Bullwinkle" },
            new Author() { Name = "Antonio Cisternino", PenName = "Mr. Peabody" }
        },
    Published = 2007 };

It will serialize as follows (Carriage returns added for readability):

Book.Title=Expert+F#&Book.Authors.Author.Name=Don+Syme&Book.Authors.Author.PenName=Rocky&
Book.Authors.Author#2.Name=Adam+Granicz&Book.Authors.Author#2.PenName=Bullwinkle&
Book.Authors.Author#3.Name=Antonio+Cisternino&Book.Authors.Author#3.PenName=Mr.+Peabody&Book.Published=2007

NOTE: Internally the Url Form Encoded formatter converts items to xml and sorts them alphabetically, which is how the DataContractSerializer reads them by default. If the data contract is part of an inheritance hierarchy and/or data members are explicitly ordered, this formatter will not work properly (See more here).

NOTE: The WcfRestContrib.ServiceModel.Web.WebServiceHost allows you to specify configuration based behaviors if you do not want to specify this declaratively. See more about it under Declarative Binding & Behavior Overview.