WCF Web API–Elementary programming model

This is the first post on a series about the new Preview 4 of WCF Web API. In this post, I will start presenting the elementary aspects of the programming model.

Service classes/Resource classes and operations

It all starts with a class annotated with the ServiceContractAttribute attribute, usually called the resource class. In the WCF Web API, this class is just a container for methods that will handle HTTP requests for a set of related URIs. In WCF terminology, these methods are called operations.

As an example, consider the management of a “to do” list. A resource class for such scenario will typically contain methods/operations to handle the following HTTP methods:

  • GET the “to do” list;
  • POST a new “to do” into the list;
  • GET a specific “to do”;
  • DELETE a specific “to do”;
  • PUT an update to an existing “to do”.

This results in the following class.

    [ServiceContract]
    class TodoResource
    {
        [WebGet(UriTemplate = "")]
        HttpResponseMessage GetAllToDos(){...}

        [WebInvoke(UriTemplate = "", Method = "POST")]
        HttpResponseMessage PostNewTodo(HttpRequestMessage req){...}

        [WebGet(UriTemplate = "{id}")]
        HttpResponseMessage GetToDo(int id){...}
        
        [WebInvoke(UriTemplate = "{id}", Method = "DELETE")]
        HttpResponseMessage DeleteToDo(int id){...}
        
        [WebInvoke(UriTemplate = "{id}", Method = "PUT")]
        HttpResponseMessage UpdateToDo(int id, HttpRequestMessage req){...}        
    }

Association between HTTP requests and Operations

The association between an HTTP request and the operation  that will handle it is done via the WebGetAttribute and WebInvokeAttribute attributes. Notice how each method in the above class is annotated with one of these attributes.

The association uses two properties of a HTTP request:

  • The request URI;
  • The request method (e.g. GET, POST)

The WebGetAttribute associates the annotated method to requests with GET method and an URI that matches the WebGetAttribute .UriTemplate property.

The WebInvokeAttribute associates the annotated method to requests with a HTTP method contained in the WebInvokeAttribute.Method property, and an URI that matches the WebGetAttribute.UriTemplate property.

Operation Parameters

A resource class doesn’t have to derive from any class or interface. This means that there isn’t any language contract that an operation method must implement. Namely:

  • Operation methods can have any name;
  • The parameters and return type of an operation method are not defined by a base class or interface.

Instead, we can see the operation parameters as dependencies that WCF will try to resolve during runtime, using information derived from the request. In future posts, I will describe how this resolution is performed and how it can be extended.

Similarly, there isn’t any language contract specifying the return type of an operation. Instead, the WCF runtime will try to use the operation’s return value to build a HTTP response.

This absence of language contracts means that errors are not caught at compile time. Instead, if the operation parameters cannot be resolved, an error will occur only at service startup.

The HttpResponseMessage class

One of the return types allowed for an operation is the HttpResponseMessage type, which is a strongly typed representation of an HTTP response.

For instance, the GetAllToDos operation,  which handles a GET over the “to do” collection, uses it to completely control the response.

[WebGet(UriTemplate = "")]
HttpResponseMessage GetAllToDos()
{
    return new HttpResponseMessage()
    {
        StatusCode = HttpStatusCode.OK,
        Content = new StringContent(
            String.Concat(_repository.All.Select(t => t.ToString())))
    };
}                  

Notice the following:

  • The StatusCode property is of of type HttpStatusCode, which is an enum containing all the standard status codes.
  • The response body is controlled via the Content response property. In this case, a string type content is used (StringContent class), which results in a “text/plain” media type.

The HttpRequestMessage class

One of the accepted operation parameter types is the HttpRequestMessage, which is a strongly typed representation of a HTTP request.

For instance, the PostNewToDo operation uses this type as a parameter to obtain the “to do” representation from the request body

[WebInvoke(UriTemplate = "", Method = "POST")]
HttpResponseMessage PostNewToDo(HttpRequestMessage req)
{
    var body = req.Content.ReadAsString();
    dynamic formContent = FormUrlEncodedExtensions.ParseFormUrlEncoded(body);
    string description = formContent.Description;
    if (description == null)
    {
        return new HttpResponseMessage()
            {
                StatusCode = HttpStatusCode.BadRequest
            };
    }
    var td = new ToDo(description);
    _repository.Add(td);
    var response = new HttpResponseMessage();
    response.StatusCode = HttpStatusCode.Created;
    string uriString = req.RequestUri.AbsoluteUri + "/" + td.Id.ToString();
    Uri uri = new Uri(uriString);
    response.Headers.Location = uri;
    response.Content = new StringContent(uri.AbsoluteUri, Encoding.UTF8, "text/uri-list");
    return response;
}

Notice:

  • The parsing of the request into a dynamic object;
  • If the body does not contain a “description”, then a “Bad Request” response is returned;
  • If the new “to do” is successfully created, then a “Created” response is returned with a “Location” header containing this new “to do” URI.

UriTemplate variables

An operation can also have parameters whose names equals an URI template variable. For instance, the GetToDo operation uses this feature to obtain the “to do” identifier.

[WebGet(UriTemplate = "{id}")]
HttpResponseMessage GetToDo(int id)
{
    ToDo td = _repository.All.Where(t => t.Id == id).FirstOrDefault();
    if (td == null)
    {
        return new HttpResponseMessage()
        {
            StatusCode = HttpStatusCode.NotFound
        };
    }
    return new HttpResponseMessage()
    {
        StatusCode = HttpStatusCode.OK,
        Content = new StringContent(td.ToString())
    };
}

Notice:

  • The id parameter, that will be bound to the id variable on the “{id}” URI template.

The HTTP protocol as a first class concept

The initial version of WCF was heavily based on the SOAP model, where HTTP is just one of the available mechanisms to transport SOAP messages. The transport independence of the SOAP model means that the transport mechanisms are, for the most part, abstracted away behind a binding. 

However, WCF Web API aims to provide a “first class experience” for using HTTP. This means exposing HTTP as a transfer protocol in its full glory and not hiding it.

The use of the HttpRequestMessage and HttpResponseMessage types, as parameter and return type of the operations, are a way of giving direct access to the HTTP protocol, without some of the parsing and encoding complexity.

Notice also that the HTTP request information is explicitly passed into an operation as an HttpRequestMessage and not obtained from the “current context" (e.g. WebOperationContext.Current on previous versions of WCF).

The HttpRequestMessage and HttpResponseMessage classes belong to the Microsoft.Net.Http and are not dependent on WCF. Namely, these classes can be easily instantiated without having to use any WCF artifact.

These two aspects are essential for the operation testability, as we shall see in future posts.

The full code for this example can be found at github.

In the next post, I will describe how to host this service class/resource class.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s