O'Reilly logo

RESTful .NET by Jon Flanders

Stay ahead with the world's most comprehensive technology and business learning platform.

With Safari, you learn the way you learn best. Get unlimited access to videos, live online training, learning paths, books, tutorials, and more.

Start Free Trial

No credit card required

Chapter 4. Programming Read/Write Services

In the previous chapter, you were introduced to the WCF 3.5 web programming model and the major pieces of its infrastructure. You used the programming model to write a read-only RESTful service, and used the infrastructure to deploy and expose it.

While it could be that some of the services you build will be read-only, it is more likely that your services will include other parts of the uniform interface in addition to GET. In this chapter, I’ll show you how to put the WCF 3.5 web programming model to work in building a read/write service that allows user agents to create, modify, and delete resources.

POST, PUT, and DELETE

Chapter 1 discussed REST and the architectural constraints of the uniform interface. See Figure 4-1 to refresh your memory about the uniform interface and how it should work.

REST uniform interface
Figure 4-1. REST uniform interface

Recall from Chapter 3 that WCF enables a RESTful programming model by allowing annotation on methods via attributes. These attributes specify which method should be invoked for each URI, and which part of the uniform interface each method implements. For example, WebGetAttribute will implement GET, and its UriTemplate property value specifies the URI to which the method will respond.

All other verbs in the uniform interface (POST, PUT, and DELETE) are implemented using the WebInvokeAttribute. WebInvokeAttribute also allows you to customize the URI that the method will respond to through its own UriTemplate property. It also allows you to set the HTTP verb so that you can not only implement the remainder of the uniform interface, but you can implement HTTP verbs that are not part of the uniform interface. Because we already examined GET and WebGetAttribute at length in Chapter 3, this chapter will focus on WebInvokeAttribute.

Using WebInvokeAttribute

For this discussion, we will revisit the user/membership system example from Chapter 1 by creating the code to implement that service using WCF, instead of just discussing it in the abstract. The service from the last chapter is really a read-only service for the most part (although not being overly familiar with the biological taxonomy system perhaps there are more changes than I am aware of), so I think this example is better for a read/write service. To refresh your memory, the sample service is a membership system that stores information about users. First, let’s walk through the RESTful design steps for this service in a slightly abbreviated fashion.

Resources

Our example service will expose the following resources:

  • All users

  • A particular user delineated by the user’s unique identifier

URIs and Uniform Interface

Table 4-1 shows the URIs and the parts of the uniform interface that we will implement for each URI in our example.

Table 4-1. User service URIs

URI

Method

Description

Output

Input

/users

GET

Returns a representation of all users in the system

users collection

n/a

/users

POST

Creates a new user in the system, expects a representation of the user in the HTTP body

user

user (without the user_id specified)

/users/{user_id}

GET

Returns the representation of a particular user, based on the user’s identifier in the system

user

n/a

/users/{user_id}

PUT

Modifies a user resource

user

user

/users/{user_id}

DELETE

Deletes a user from the system

n/a

n/a

It is important to reiterate here that you don’t have to implement the entire uniform interface for all resources; the same service may expose read-only resources alongside read/write resources. For example, the /users resource is read-only and does not implement the DELETE method, because even if there aren’t any users, we still want that resource to be there.

Representations

For this particular application, let’s use a custom XML format. The following code defines two .NET classes you’ll use to represent the data: User represents each user, and Users represents the collection of users.

[CollectionDataContract(Name = "users", Namespace = "")]
public class Users : List<User>
{
}
[DataContract(Name = "user", Namespace = "")]
public class User
{
    [DataMember(Name="id",Order=1)]
    public string UserId;
    [DataMember(Name = "firstname", Order = 2)]
    public string FirstName;
    [DataMember(Name = "lastname", Order = 3)]
    public string LastName;
    [DataMember(Name = "email", Order = 4)]
    public string Email;
}

Implementation

Next, we need a class annotated with the ServiceContractAttribute that has the ability to keep track of users. For this example we’ll use a static data member with the list of users:

[ServiceContract]
public class UserService
{
   static Users _users = new Users();
   //rest of the implementation to follow
}

Yes, this implementation flies in the face of the concept of statelessness in REST because the service holds onto state (the list of users). Right now, however, we need to focus on the semantics of writing the service infrastructure pieces of code with WCF. Instead of this stateful implementation, imagine instead that we are storing the list of users in a backend database and that the service implementation is totally stateless.

POST

POST is the part of the uniform interface that is typically used to create a new resource. To implement POST as part of our RESTful WCF service, we annotate the CLR method with the WebInvokeAttribute. We set the WebInvokeAttribute.Method property to the string “POST” (although POST is the default, being explicit is usually a better policy) and then we set the UriTemplate property to the template we want this method to respond to. This will cause WCF to call the method on our service instance when a request comes to the endpoint with a URI that matches the template when the HTTP verb used in the request is POST.

The UriTemplate follows the same rules on the WebInvokeAttribute as it does on WebGetAttribute. In fact, all of the UriTemplate definitions from all methods are parsed and added to the endpoint’s UriTemplateTable in exactly the same way. When matching against the UriTemplateTable, not only does the WCF web-dispatching infrastructure look at the URI, it also looks at the HTTP verb from the request. This is why the UriTemplate value can be the same for multiple service methods, as long as each accepted HTTP verb is different. Example 4-1 shows the first part of the UserService definition, which relates to the top-level URI ("/users").

Example 4-1. Top-level URI implementation
[WebGet(UriTemplate = "/users")]
[OperationContract]
public Users GetAllUsers()
{
    return _users;
}
[WebInvoke(UriTemplate = "/users", Method = "POST")]
[OperationContract]
public User AddNewUser(User u)
{
    u.UserId = Guid.NewGuid().ToString();
    _users.Add(u);
    return u;
}
[WebGet(UriTemplate = "/users/{user_id}")]
[OperationContract]
public User GetUser(string user_id)
{
    User u = FindUser(user_id);
    return u;
}

Note that UriTemplate value is the same for both GetAllUsers and AddNewUser, but one uses the WebGetAttribute and one uses WebInvokeAttribute. The Method property of WebInvokeAttribute on AddNewUser is POST, which is the method we’re most interested in at the moment. The WCF web-dispatching infrastructure will use the HTTP verb to differentiate requests to this URI and will route them to the appropriate method.

Note

The code in Example 4-1 sets WebInvokeAttribute.Method to POST, even though POST is the default. Explicitly defining default values (which would be used even if you left them out) makes it easier to scan a contract for the uniform interface.

Another interesting thing about this design is that it does not allow the service client to set the resource identifier (in this case User.UserId). This is why the URI for both getting all users and creating a new user is the same. In this case, the "/users" resource acts like a factory when POST is used, and even if the UserId property is set, it will be overwritten.

Your own design might end up being different in this regard. If you decide to allow users to select the identifier for the resource, the URI for creating the new resource will include the identifier and will thus be different from the collection URI. If the design used here followed that pattern, the UriTemplate for the AddNewUser method would be "/users/{user_id}". It would also be expected that the HTTP verb would be PUT instead of POST to create the user resource. In most cases, it is difficult to design a service that allows clients to decide on the identifiers because each identifier must be unique.

Because of this choice, the AddNewUser method in Example 4-1 doesn’t have a UriTemplate-based parameter for user_id, but it does have a parameter: the complex User type, which we defined earlier. It’s expected that when you implement POST and PUT from the uniform interface you will accept a request body as part of the incoming HTTP request message (DELETE on the other hand isn’t expected to have a request body). When you use the WebInvokeAttribute on a method, the first parameter(s) of the method are expected to be the template matches from the UriTemplate definition if there are any. The last parameter is expected to be deserialized from the incoming HTTP message body.

In Chapter 1, we looked at hypothetical images of what the requests and responses to this service would look like. Let’s now look at images of actual interactions between a user agent and the service, using a special user agent called Fiddler.

Fiddler is an incredibly useful tool for carrying out complex interactions between websites and web services. Not only can it spy on requests going from a user agent to a server, it can also allow you to build arbitrary HTTP requests using its Request Builder functionality. See http://www.fiddlertool.com/ for more information about this useful tool.

Note

The Fiddler Request Builder tab allows you to create arbitrary HTTP requests using different HTTP verbs and different representations as the request body. It also allows you to see the response that the service returned from those requests. This is an invaluable tool when building services of any kind, but with RESTful services it can become the first path testing client.

In Chapter 10, I’ll show you how to implement clients using WCF. For now, we will concentrate on the service syntax and programming model using the Fiddler tool.

The first thing we will do is view the current collection of users by passing a GET request to the root URI. Figure 4-2 shows the Request Builder HTTP GET request, and Figure 4-3 shows the Session Inspector tab view for the same request.

Using Fiddler to GET to root URI
Figure 4-2. Using Fiddler to GET to root URI
Fiddler Session Inspector view of GET request
Figure 4-3. Fiddler Session Inspector view of GET request

Note

In this case we are hosting the WCF RESTful service inside of IIS, using the .svc file capabilities instead of self-hosting, primarily for ease of deployment and because using Fiddler is slightly easier when using port 80 for HTTP requests. See Chapter 5 for more details about hosting options.

In Figure 4-3, you can see that the response to the HTTP GET request is an empty collection. Our next step, then, is to add a user to the collection using a POST request to the same URI, including an entity body of the right media type. Figure 4-4 shows this request, and Figure 4-5 shows the response.

Creating a new user resource with HTTP POST to the root URI
Figure 4-4. Creating a new user resource with HTTP POST to the root URI
POST request and result in Fiddler Session Inspector
Figure 4-5. POST request and result in Fiddler Session Inspector

One important thing to note in Figure 4-4 is the Content-Type header. The Content-Type header is essential when using RESTful services in general, but is especially important when making requests to RESTful services. If you don’t have a Content-Type header in your HTTP request to a WCF service, you’ll always get a “415 Missing Content Type” status code. You don’t need the Content-Type header when making a GET request, since there isn’t any entity body when making a GET request.

In Figure 4-5 you can see the Fiddler Session Inspector tab. The raw option is selected, and the service responded with a user resource (as shown by the new unique value in the id element).

If we make another GET request to the root URI, we will see the newly added member. Notice that in Figure 4-6 in the response content body that the id element now has a value, and the unique identifier that is now part of the newly created user resource.

Fiddler Session Inspector view of a GET request showing a newly added user resource
Figure 4-6. Fiddler Session Inspector view of a GET request showing a newly added user resource

We can now use this identifier as part of a GET request for that particular resource (Figure 4-7).

Single resource GET request
Figure 4-7. Single resource GET request

PUT

At this point, the service has one user resource, created via a POST request. Let’s now turn our attention to using PUT.

Example 4-2 shows the service method that implements PUT and modifies a specific user resource.

Example 4-2. Service method that implements PUT
[WebInvoke(UriTemplate = "/users/{user_id}", Method = "PUT")]
[OperationContract]
public User UpdateUser(string user_id,User update)
{
    User u = FindUser(user_id);
    UpdateUserInternal(u, update);
    return u;
}

The details of the UpdateUserInternal aren’t very important as it’s just a simple copy of fields from the new user resource into the old, except for the UserId field. The more interesting bit of code from Example 4-2 is that the UriTemplate value of this WebInvokeAttribute is the same as the UriTemplate value on the single user resource GET method (the GetUser method from Example 4-1). Remember, you can have multiple methods with the same UriTemplate value, as long as the HTTP verb is different. The GetUser method uses the WebGetAttribute; its method will inherently implement GET, so requests to a particular user’s URI will be routed to the GetUser method when the HTTP verb in the request is GET. The UpdateUser method will be called when a request arrives for a specific user’s URI when the HTTP verb is PUT because the WebInvokeAttribute.Method on the UpdateUser method is set to PUT.

To modify a resource, we can make a PUT request to the user’s URI, passing the correct user resource representation (which in this case is XML). On success, the service returns the same resource as the body of its response. You can see the request in Figure 4-8 and the response in Figure 4-9.

Using a PUT request to modify a user resource
Figure 4-8. Using a PUT request to modify a user resource
PUT request and response in the Fiddler Session Inspector view
Figure 4-9. PUT request and response in the Fiddler Session Inspector view

You can see in Figure 4-8 that we changed the resource by modifying the email address. The service returns a “200 OK” response code and returns the newly modified resource as the response body.

DELETE

At this point, you probably have a pretty good idea of how the implementation of DELETE is going to progress. Example 4-3 shows the code used to implement DELETE.

Example 4-3. Implementing DELETE
[WebInvoke(UriTemplate = "/users/{user_id}", Method = "DELETE")]
[OperationContract]
public void DeleteUser(string user_id)
{
    User u = FindUser(user_id);
    _users.Remove(u);
}

You can see the interaction between the client and the service using DELETE in Figures 4-10 and 4-11.

Using DELETE in Fiddler
Figure 4-10. Using DELETE in Fiddler
DELETE request and response in the Fiddler Session Inspector view
Figure 4-11. DELETE request and response in the Fiddler Session Inspector view

RESTful convention dictates that DELETE will not accept or return a representation. There really isn’t anything else special about implementing DELETE, other than making sure to set the WebInvokeAttribute.Method property appropriately.

Full service implementation

Example 4-4 shows the entire service implementation from top to bottom.

Example 4-4. Full read/write service implementation
[ServiceContract]
public class UserService
{
    static Users _users = new Users();

    [WebGet(UriTemplate = "/users")]
    [OperationContract]
    public Users GetAllUsers()
    {
        return _users;
    }
    [WebInvoke(UriTemplate = "/users", Method = "POST")]
    [OperationContract]
    public User AddNewUser(User u)
    {
        u.UserId = Guid.NewGuid().ToString();
        _users.Add(u);
        return u;
    }
    [WebGet(UriTemplate = "/users/{user_id}")]
    [OperationContract]
    public User GetUser(string user_id)
    {
        User u = FindUser(user_id);
        return u;
    }
    User FindUser(string user_id)
    {
        User ret = null;
        var result = (from u in _users
                      where u.UserId == user_id
                      select u).Single();
        if (result != null)
            ret = result;
        else
            ret = new User();
        return ret;

    }
    [WebInvoke(UriTemplate = "/users/{user_id}", Method = "PUT")]
    [OperationContract]
    public User UpdateUser(string user_id, User update)
    {
        User u = FindUser(user_id);
        UpdateUserInternal(u, update);
        return u;
    }

    private void UpdateUserInternal(User u, User update)
    {
        u.Email = update.Email;
        u.FirstName = update.FirstName;
        u.LastName = update.LastName;

    }
    [WebInvoke(UriTemplate = "/users/{user_id}", Method = "DELETE")]
    [OperationContract]
    public void DeleteUser(string user_id)
    {
        User u = FindUser(user_id);
        _users.Remove(u);

    }
}

Summary

In this chapter, you learned how to finish implementing the uniform interface using WCF. Use WebInvokeAttribute to implement any HTTP method other than GET, and use the WebInvokeAttribute.Method property to specify which HTTP method the CLR method should respond to. You can customize the URI using the WebInvokeAttribute.UriTemplate property. WCF routes messages to the methods on instances of your service type by looking for a match based on the URI and the HTTP verb.

There is still more that you can do to make your services compliant with the constraints of REST. Chapter 11 has more information about extending beyond the basic infrastructure of the WCF web-programming model and using the full breadth of HTTP in your service.

With Safari, you learn the way you learn best. Get unlimited access to videos, live online training, learning paths, books, interactive tutorials, and more.

Start Free Trial

No credit card required