Implementing REST Web services Part 2

Mea Culpa

Yesterday’s post showed a rudimentary WCF Rest service and how we need to change the system.serviceModel tag to support a REST service rather than a SOAP based WCF service. The service returned a string. The reason I set that up was because an object must be serialized prior to being sent back. Originally I thought that had to be done by the developer.

Nope.

The serialization of the object is done by the WCF infrastructure prior to sending it back to the calling function. For this reason there is no need to serialize the object yourself.

The revised interface is as follows;

[ServiceContract]
public interface IUser
{
    [WebGet(UriTemplate = "Login?email={email}&password={password}")]
    [OperationContract]
    [XmlSerializerFormat]
    LoginResult Login(String Email, String Password);
}

and the implementation of the Login method is

public LoginResult Login(string Email, string Password)
{
    RegisteredUserDataSource ds = null;
    String sessionId            = String.Empty;
    LoginResult result          = null;

    try
    {
        result                   = new LoginResult();
        result.Error             = new Error();
        result.Error.ErrorNumber = 0;
        result.Error.Message     = "OK";
        ds                       = new RegisteredUserDataSource();
        sessionId                = ds.LoginUser(Email, ds.EncryptString(Password), HostAddress());

        if (sessionId == String.Empty)
        {
            result.Error.ErrorNumber = 1001;
            result.Error.Message     = "Unrecognised Email and Password combination";
        }
    }
    catch(System.Exception ex)
    {
        result.Error.Message     = ex.Message;
        result.Error.ErrorNumber = 1002;
    }
    finally
    {
        ds               = null;
        result.SessionId = sessionId;
    }

    return result;
}

There are two classes of note here. The first is the Error Object. This will allow us to transfer back to the client the details of any error. This class if defined as follows;

[DataContract]
public class Error
{

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

    [DataMember]
    public String Message
    {
        get;
        set;
    }
}

At the moment this should be enough to let the caller know what went wrong. It consists of just an error number and a message.

The other object is the LoginResult object. This inherits from a third object called the BaseReturnObject – initially this will just have the Error object, but by doing this it gives us the option of adding more common properties should the need arise.

[DataContract]
public class BaseReturnObject
{
    [DataMember]
    public Error Error { get; set; }
}

and the LoginResult object itself.

[DataContract]
public class LoginResult : BaseReturnObject
{
    [DataMember]
    public String SessionId
    {
        get;
        set;
    }
}

So now we have the object for the method to return.

The Client End

There is not much point in a service if there is nothing to consume it! So now we have to write the code to consume the service that has just been written but before I do lets consider the object that is returned back from the service. I have split this out to a separate module in the project. The reason for this is to enable reuse. The last thing I want to do write two versions of every return object – eventually I can see this being 100’s of objects! By splitting it out I can set a relationship to the project from both the client and the service.

Essentially to call a REST service what we need to do is make a web call to the service and examine the string returned for the results of our call. To find out the format of the call we need to go back to the service code. Below is the declaration of the Login Service

[WebGet(UriTemplate = "Login?email={email}&password={password}")]
[OperationContract]
[XmlSerializerFormat]
LoginResult Login(String Email, String Password);

What we are interested here is the WebGet attribute. This tells us the format of service call for this method and we add the string to the baseUri of the service. Just temporarily I have set a variable to this baseUri but long term it would be better if this came from a configuration setting.

String baseUri = "http://127.0.0.1:8080/User.svc/";

And Later we add to this the address to the service.

url = baseUri + String.Format("Login?email={0}&password={1}", txtEmail.Text, txtPassword.Text);

Now the service is designed to use the QueryString parameter  to represetn the service parameters. I’ve used String.Format to add the required QueryString parameters to the Uri. You will also notice that the parameters denoted by {email}  and  {password} are matched by the calling parameters of the service.

Now we have the address we need to call we can make the call to the service and check the result.

HttpWebRequest request = WebRequest.Create(url) as HttpWebRequest;

using (HttpWebResponse response = request.GetResponse() as HttpWebResponse)
{
    reader           = new StreamReader(response.GetResponseStream());
    result           = reader.ReadToEnd();
    serializedResult = Server.HtmlDecode(result);
    resultObj        = (LoginResult)Toolbox.Deserialize(typeof(LoginResult), serializedResult);

    if (resultObj.Error.ErrorNumber != 0)
    {
        throw new Exception(resultObj.Error.Message);
    }

}

As this is currently being called from the Web Page it is a synchronous call. Silverlight when I come around to it will need a asynchronous call. First off is to make the request of the method which is what the WebRequest.Create call. Then what we do is check the response with the GetResponse method which returns back and an instance of HttpWebResponse. Because the HttpWebResponse object inherits from IDisposable we can use the ‘using’ construct – which will automatically dispose of the object when we have finished.

Now a response is sent back to the calling function as a stream. We make a call to GetResponseStream to return this stream and then we read the stream into a string.

Now before sending back the results certain characters are replaced with escape sequences – so what we need to do is replace these escape sequences with the correct charactrers – which is why we make a call to the Server.HttpDecode method.

Now we have a string which can be deserialized into a .Net class for easier manipulation.

I have written a static toolbox method to do this for me – just to avoid having to repeat it – making the class and method both static means there is no need to create an instance of the Toolbox class.

The code for the Deserialize method is as follows;

public static Object Deserialize ( Type type, String SerializedObject )
{
    Object resultObj = null;

    ASCIIEncoding encoder       = null;
    MemoryStream ms             = null;
    XmlSerializer serializer    = null;
    XmlTextWriter xmlTextWriter = null;

    encoder = new ASCIIEncoding();
    ms = new MemoryStream(encoder.GetBytes(SerializedObject));
    serializer = new XmlSerializer(type);
    xmlTextWriter = new XmlTextWriter(ms, Encoding.ASCII);
    resultObj = serializer.Deserialize(ms);

    return resultObj;
}

So there we have it – a client to call the REST service.

Implementing REST Web services Part 1

Introduction

I want my project to support numerous clients form factors. This is becoming even more important now the number of form factors has increased – what with servers, desktops, laptops, notebooks, net books, slates (of various sizes) and smart phones – that is before we get to OS such as Android, Windows Phone 7, iOS and that is just phones! . All have differing screen sizes but more importantly the quality of the connection to the internet differs greatly – the speed of a home or work based network is a lot faster than the wireless cell network.

Although using WCF is fairly easy because of things like the SOAP envelope the amount of information transferred over the wire is that much greater than just the data being transferred. The SOAP envelope makes connecting to a WCF service easier – because the service itself informs the client of the data format. REST allows for quicker transfer of data, but sacrifices some of the simplicity. On the other hand REST uses nothing more than HTTP and that is widely available. Anyway much of the extra complexity can be hidden behind a object class which can be implemented in any language that is appropriate.

So any way this prompted me to look at the practicalities of implementing the web services in my project in the REST format. This would then provide a light weight service that can be called from any service going.

As it happens when doing this I found another advantage. Back when I first did ASPX Web Services a page was created with a full test harness – I could test the service just by going to an address in my browser. This is particularly useful when wanting to test a rollout – I found this much more awkward with WCF – although there is a test client. In REST we get this option back – just by going to the web address associated with the call you want to test.

Getting Started

Starting the creation of a REST web service is exactly the same as with a WCF Service. Once the WCF Service is created we need to modify the setup to make it a REST service (OK possible are you NUTS moment altering a web.config. I have a User service and below is the ServiceModel tag from the web.config of the web service.

  <system.serviceModel>
      <behaviors>
          <endpointBehaviors>
              <behavior name="webBehavior">
                  <webHttp/>
              </behavior>
          </endpointBehaviors>
      </behaviors>
      <services>
          <service name="MyCompanyService.User">
              <endpoint address="" behaviorConfiguration="webBehavior" binding="webHttpBinding" bindingConfiguration="" contract="MyCompanyService.IUser" />
              <endpoint address="rest" behaviorConfiguration="webBehavior" binding="webHttpBinding" bindingConfiguration="" contract="MyCompanyService.IUser" />
          </service>
      </services>
  </system.serviceModel>

The principle change was the creation of a new behaviour (webBehavior) and changes to the binding to use webHttpBinding.

Now on to creating the initial service.

The first service has to do with Users. First up is the Login method so deleting the DoWork method from the interface I am going to replace it with a Login method that takes two parameters; email and password.

[ServiceContract]
public interface IUser
{
    [WebGet(UriTemplate = "Login?email={email}&password={password}",
            ResponseFormat=WebMessageFormat.Xml)]
    [OperationContract]
    String Login(String Email,String Password);
}

Couple of changes here from a traditional WCF service in that we give it a an extra attribute; the WebGet attribute. The first parameter here is the UriTemplate – this determines the web address that will be used to access this service. In this instance we will add ‘/login?email=myemail@mydomain.com&password=mypassword’ to the address of the service. I have also added the ResponseFormat and set it to Xml – this is because it allows me to use serialization to transfer any object to an Xml String from the service and the client.

[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
public class User : IUser
{

    public string Login(string Email, string Password)
    {
        return String.Format("Hello {0} your password is {1}",Email,Password);
    }
}

This is just for testing purposes so all it does is pass back a string containing the email and password. It is kind of a REST equivalent of ‘Hello World’. So if we now run our project.

When the project is running start a new instance of IE (or any browser) and type the following in the address bar;

 http://127.0.0.1:8080/User.svc/Login?email=myemail@mydomain.com&password=secretword

What you should get is something like the following;

image

This shows a browser and the string passed back from the service – thereby demonstrating it works!

Out of interest checking the source of the page gives the following XML

So that is the service setup. I’m going to add to this once I have implemented something a bit more interesting than yet another ‘Hello World’

2010 in review

The stats helper monkeys at WordPress.com mulled over how this blog did in 2010, and here’s a high level summary of its overall blog health:

Healthy blog!

The Blog-Health-o-Meter™ reads This blog is doing awesome!.

Crunchy numbers

Featured image

A Boeing 747-400 passenger jet can hold 416 passengers. This blog was viewed about 6,200 times in 2010. That’s about 15 full 747s.

In 2010, there were 9 new posts, not bad for the first year! There were 18 pictures uploaded, taking up a total of 2mb. That’s about 2 pictures per month.

The busiest day of the year was September 12th with 66 views. The most popular post that day was Using a Custom Membership Provider in an MVC Application.

Where did they come from?

The top referring sites in 2010 were digg.com, google.co.in, google.com, michael-jackson-secret-exposed.xpac.info, and android-vs-ipad.co.cc.

Some visitors came searching, mostly for mvc custom membership provider, custom membership provider mvc, mvc own membership, mvc custom membership, and custom membership provider.

Attractions in 2010

These are the posts and pages that got the most views in 2010.

1

Using a Custom Membership Provider in an MVC Application June 2010
3 comments

2

Sending a confirmation email after registration April 2010

3

Using the Companies House GovTalk Service to retrieve Company Details July 2010

4

Connecting a WCF Service to an Model View Controller Client June 2010
1 comment

5

About January 2010