Home > English > Building a generic service using WCF Web API

Building a generic service using WCF Web API

Now that we have taken a look at the new WCF Web API let’s see what it takes to build a generic service that will work for both Silverlight and web requests. In this example we are going to basically mock our database so that we can focus completely on the service itself. In a later post I will go over what it takes to support this generic service with a generic data access layer.

As of this post, Preview 6 is available from the WCF Web API.

Okay, let’s look at what we have for our generic service below:

namespace Gofer.Web
{
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.ServiceModel.Web;
    using System.ServiceModel;
    using System.Net.Http;
    using System.Json;
    using System.Net;
    using Microsoft.ApplicationServer.Http.Dispatcher;

    [ServiceContract]
    public class GoferService<T> where T : class, new()
    {
        #region Member Variables

        private DataAccessRules _rules;
        public DataAccessRules Rules
        {
            get { return _rules; }
            set { _rules = value; }
        }

        #endregion

        #region ctor

        public GoferService(DataAccessRules rules)
        {
            _rules = rules;
        }

        #endregion

        #region Web Methods

        #region Get

        [WebGet(UriTemplate = "")]
        public HttpResponseMessage<List<T>> Get()
        {
            try
            {
                var repo = new Repository<T>(Rules);
                var result = repo.Get().ToList();
                var response = new HttpResponseMessage<List<T>>(result);
                return response;
            }
            catch (Exception ex)
            {
                var response = new HttpResponseMessage();
                response.Content = new StringContent(ex.Message);
                throw new HttpResponseException(response);
            }
        }

        #endregion

        #region Insert

        [WebInvoke(UriTemplate = "", Method = "POST")]
        public HttpResponseMessage<T> Insert(T item)
        {
            var typeName = typeof(T).Name;
            if (item == null)
            {
                var error = new HttpResponseMessage(HttpStatusCode.NotFound);
                error.Content = new StringContent(string.Format("{0} not found!", 
					typeName));
                throw new HttpResponseException(error);
            }

            try
            {
                var schema = (from c in Rules.Schemas 
							  where c.ClassName == typeName 
							  select c).FirstOrDefault();
                var pkey = schema.GetPrimaryKey(schema.ClassName);
                var repo = new Repository<T>(Rules);
                int id = repo.Insert(item);
                ReflectionHelper.SetPropertyValue(item, pkey, id);
                var response = new HttpResponseMessage<T>(item);
                response.StatusCode = HttpStatusCode.Created;
                return response;
            }
            catch (Exception ex)
            {
                var response = new HttpResponseMessage();
                response.Content = new StringContent(ex.Message);
                throw new HttpResponseException(response);
            }
        }

        #endregion

        #region Update

        [WebInvoke(UriTemplate = "{id}", Method = "PUT")]
        public HttpResponseMessage<T> Update(T item, int id)
        {
            var typeName = typeof(T).Name;
            if (item == null)
            {
                var error = new HttpResponseMessage(HttpStatusCode.NotFound);
                error.Content = new StringContent(string.Format("{0} not found!", 
					typeName));
                throw new HttpResponseException(error);
            }

            try
            {
                var repo = new Repository<T>(Rules);
                repo.Update(item);
                var response = new HttpResponseMessage<T>(item);
                response.StatusCode = HttpStatusCode.Ok;
                return response;
            }
            catch (Exception ex)
            {
                var response = new HttpResponseMessage();
                response.Content = new StringContent(ex.Message);
                throw new HttpResponseException(response);
            }
        }

        #endregion

        #region Delete

        [WebInvoke(UriTemplate = "{id}", Method = "DELETE")]
        public HttpResponseMessage<int> Delete(int id)
        {
            try
            {
                var repo = new Repository<T>(Rules);
                return repo.Delete(id);
            }
            catch (Exception ex)
            {
                var response = new HttpResponseMessage();
                response.Content = new StringContent(ex.Message);
                throw new HttpResponseException(response);
            }
        }

        #endregion

        #endregion
    };
}

NOTE: I have simplified this service a bit to show you how to build your own generic service.

The first thing to note with this service is the ServiceContract attribute. As of Preview 6, this is no longer required but I included it for demonstration purposes. As you can see from the contructor, I am using dependency injection (DI) to provide an object called DataAccessRules. Basically, this object allows me to specify what connection string to use that is stored in the web.config file. This is important as I want to make sure that this service is fully generic and allows me to pull data from differing databases.

Next, we see the Get method. This method allows us to get our data. As of Preview 5, we don’t need to provide an empty string for the default UriTemplate but I decided to show it to you anyways. With the Get method, I am returning an HttpResponseMessage<List<T>> object. I have a Repository object that provides access to all my underlying data. I have the repository return me a list of items of type T and then create a new HttpResponseMessage passing in the List<T> to the constructor. By default the status code of the object set to Ok which is equivalent to 200. Finally, since this service must now be marshaled to the client, we want to be very careful that we handle any exceptions and wrap them up in objects that can be used by our clients. Out of the box, the WCF Web API plays very nice with browsers and you can see most of your exceptions without any extra work but it is when we are dealing with clients like Silverlight that we need to be more careful.

We can now look at what is required for inserting new records. This method uses a WebInvoke attribute compared to the WebGet that we saw in our get method. With the WebInvoke attribute we handle all other HTTP verbs that we want to use. For this request, we are going to handle a POST. This method returns an instance of an HttpResponseMessage<T> as well as takes in an instance of the generic type T. We pull the name of the type and put that in a variable. We test for a null input condition and throw the correct exception correspondingly. In our Rules object, we have some metadata that describes how to get the Primary Key for our object. This rule is in the format of a Expression<<Func<string,string>> and allows delayed evaluation. It isn’t until the GetPrimaryKey method is executed that the Expression<Func<string,string>> is evaluated. This is a handy trick as it allow us to define rules per object or namespace by passing in a lambda expression.

Once we have the name of the key, we then go ahead and use the Repository object and Insert a new record. What we do next is use some reflection to set the underlying object key property with the value returned by the Repository. Finally, we create an instance of an HttpResponseMessage<T> passing in the generic instance as well as setting the StatusCode to Created. We handle any exceptions in this method exactly the same.

The Update method basically operates the same. It uses a PUT operation. The Repository passes the generic object and performs the Update. The method returns an HttpResponseMessage<T> object once the operation successfully completes.

The final operation is the Delete. It uses a DELETE operation. The Repository passes the integer value and performs the Delete. The method returns an HttpResponseMessage<int> object once the operation successfully completes.

We now have our generic service defined. In the next post, we will look at what it takes to expose this service from a web project.

About these ads
Categories: English Tags: ,
  1. No comments yet.
  1. December 20, 2011 at 1:13 pm

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

Follow

Get every new post delivered to your Inbox.

Join 197 other followers

%d bloggers like this: