Sep 192012
 
Share...Tweet about this on TwitterShare on FacebookShare on Google+Share on StumbleUponShare on LinkedInPin on PinterestShare on TumblrShare on RedditDigg this

In this short tutorial I will show how to create quickly a RESTful service by using Visual Studio 2012, ASP.NET Web API and Advanced REST Client.

Download a fully working example that covers all the code mentioned in the post: FirstAspNetWebApi_20120920.zip
If you liked the article, please share this page to your twitter followers Tweet This.

Let’s quickly learn some basic concepts:

RESTful service

REST acronym stands for REpresentational State Transfer. In the latest years REST is emerging as a predominant Web service design model. As another alternative we have Web Services built around SOAP.

RESTful services are fully built around the HTTP protocol, and use the basic HTTP commands like: GET, POST, PUT, DELETE in order to define the “action”. In simple terms, a REST Web Service is all about a Resource that can be accessed or changed by using the above mentioned HTTP methods.

What do those HTTP commands represent:

GETRetrieves a Resource
POST
  • Updates a Resource: if you are requesting the server to update one or more subordinates of the specified resource.
  • Creates Resource = POST if you are sending a command to the server to create a subordinate of the specified resource, using some server-side algorithm.
PUT
  • Creates a Resource. Use PUT if you are sending the full content of the specified resource (URL).
  • Update a Resource = PUT if you are updating the full content of the specified resource.
DELETEDeletes a Resource.

Idempotence

Idempotency guarantees that repeated invocations of a service capability are safe and will have no negative effect. The side-effects of N > 0 identical requests is the same as for a single request. The methods GET, PUT and DELETE share this property.

Message Formatting

Usually the main output formats of a restful service are JSON and XML, but obviously this is not the only option as we theoretically could return whatever type of message format we want. For instance, returning a PDF document when doing GET would be absolutely valid.

SOAP based Web Services

Another way of creating web service is by using SOAP message format as the communication between the Client and Server. Both, SOAP based and RESTful services, even though they try to solve the same issues (retrieving and getting data), the approach is very different.
Choosing REST or SOAP based services will depend upon your needs for Security, Speed, Protocols, Extensibility, Legacy Systems, etc. Is not that easy to give a recipe, but in general REST is a great tool when it comes to the AJAX dynamic pages and interoperability as it uses widely known HTTP protocol.

What is: ASP.NET Web Api

ASP.NET Web API is the latest Microsoft framework that makes it easy to build HTTP services that reach a broad range of clients, including browsers and mobile devices. ASP.NET Web API is an ideal platform for building RESTful applications on the .NET Framework.

ASP.NET Web API is build around (or better say, into) the newest ASP.NET MVC 4 framework and for the time being is the most powerful Microsoft tool when it comes to creating RESTful services. Yes, there are other possibilities as described in the article What technology for building web services in Microsoft.Net.

After this short introduction of very basic concepts, lets do some code.

ASP.NET Web API Installation

There are few ways of installing ASP.NET Web API.

  1. If you are using Visual Studio 2012, ASP.NET Web API is already pre-installed, and there is anything else needed to do.
  2. If you are using Visual Studio 2010, then there are few possibilities:

First steps

As mentioned, ASP.NET Web API is part of the ASP.NET MVC 4 Framework, and as a such in order to start, we need to create a new project by choosing ASP.NET MVC 4 Application project, and then choose the Web API as shown in the picture below:

Visual Studio will create a basic service structure, and I would like to highlight two folders:

ASP.NET Web API Visual Studio Solution Explorer
We may easily delete the HomeController as we are not interested into creating any MVC application in this example.

Routing

WebApiConfig.cs file in the App_Start folder is particularly interesting. It contains the definition of the routing needed for our service to work. As we normally do for the ASP.NET MVC application, we need to define the “route”, or better say the PATH to our service actions.

The code generated by default.

public static class WebApiConfig
{
    public static void Register(HttpConfiguration config)
    {
        config.Routes.MapHttpRoute(
            name: "DefaultApi",
            routeTemplate: "api/{controller}/{id}",
            defaults: new { id = RouteParameter.Optional });
    }
}

Please note the following:

  • routeTemplate starts with “api/”. This will generate urls like: www.agile-code.com/api/product/1. Use “api” keyword to differentiate it from the normal ASP.NET MVC route.
  • {controller} represents the actual controller. Controller in our case would correspond to the part in bold: www.agile-code.com/api/product/1
  • There is no “{action}” as we would expect it in ASP.NET MVC. As there are no actions but verbs in form of Post(), Get()… methods, there is no need for defining the Action in the route. The “{action}” is automatically known at runtime based on the HTTP verb used in the request.

RESTful service basic code

Visual Studio will take care of creating the basic skeleton of the service itself, as follows:

public class ValuesController : ApiController
{
    // GET api/values
    public IEnumerable Get()
    {
        return new string[] { "value1", "value2" };
    }

    // GET api/values/5
    public string Get(int id)
    {
        return "value";
    }

    // POST api/values
    public void Post([FromBody]string value)
    {
    }

    // PUT api/values/5
    public void Put(int id, [FromBody]string value) { }

    // DELETE api/values/5
    public void Delete(int id) { }
}

In the code above, there are few things to note:
1. ApiController is a new controller that comes as part of the ASP.NET Web API. Every RESTful service should inherit from it.
2. Methods in the service itself have the names as mentioned above as the HTTP methods, and those are bound to the proper verb at runtime by the Web API framework. It is still allowed to have methods that contain something else than the basic HTTP methods mentioned before.

Implementing something more realistic

Lets implement a ProductController, which will represent the Product resource, that for the sake of simplicity will look like:

public class Product
{
    public int Id { get; set; }
    public string Name { get; set; }
}

Service Implementation

I will show one by one the methods implementing various HTTP verbs.
Important: you will see that I am using repository keyword. This is simply a class that will keep in memory the list of Products, just for the sake of this example.

GET

GET a list of products

Get is pretty much straightforward. The Method called Get() is defined, and in our case returns a list of Products

// GET api/product
public IEnumerable Get()
{
    return repository.GetProducts();
}

for Getting back the data we may simply use the browser as well. So, if we navigate the page (in my case is http://localhost:34133/api/product), I will get back the list of products.

GET a single product

This is the code that will return one single product:

// GET api/product/5
public Product Get(int id)
{
    Product product = repository.GetProduct(id);

    if (product == null)
    {
        throw new HttpResponseException(
            Request.CreateResponse(HttpStatusCode.NotFound));
    }
    else
    {
        return product;
    }
}

The important bit in this case is that if the PRODUCT id is not found, we are going to throw an error of type HttResponseException. HTTP REsponse in this case will be “Not Found” message.

This is what happens when we are searching for an existing product:

Get single Product

and in case the product doesn’t exists (for this we will use a debugging tool called Advanced Rest Client which runs in the Chrome browser in order to test the output.).
As you see the status returned is 404 Not found, with the empty content.

POST

In order to create new content, we are going to use the POST mechanism to send the data to the server.
This is the code in the service that would create a new Product

// POST api/product
public HttpResponseMessage Post(Product product)
{
    if (ModelState.IsValid)
    {
        // this will set the ID for instance...
        product = repository.AddProduct(product);

        var response = Request.CreateResponse(
                HttpStatusCode.Created, product);

        string uri = Url.Link("DefaultApi", new {id = product.Id});
        response.Headers.Location = new Uri(uri);
        return response;
    }
    else
    {
        return Request.CreateResponse(HttpStatusCode.BadRequest);
    }
}

Creating a new resource involves few steps:
1. The client should send a POST request to api/product to create the resource.
2. REST Service should then return a 201 Created HTTP response, with the URI of the newly created resource in the Location header.
3. In case of errors “Bad Request” will be returned to the client.

as shown in the image below, the status HTTP 201 Created together with the actual data is returned to the client application.

Posting a new product

Let’s check if the product has been actually created by using the browser:
Get the list with the newly created product

as you may see, the Product with the id 6 is created.

PUT

In order to update an existing product we are going to use the PUT method. Code in the service is defined as follows:

// PUT api/product/5
public HttpResponseMessage Put(int id, Product product)
{
    if (ModelState.IsValid && id == product.Id)
    {
        var result = repository.Update(id, product);
        if (result == false)
        {
            return Request.CreateResponse(HttpStatusCode.NotFound);
        }
        return Request.CreateResponse(HttpStatusCode.OK);
    }
    else
    {
        return Request.CreateResponse(HttpStatusCode.BadRequest);
    }
}

Note the following:
1. There are two parameters. One is the ID of the product we are going to update, and the second parameter is the actual object itself.
2. If we try to update a non existing object, the HTTP code Not Found will be returned to the client
3. If there is any error happening to the code we return Bad Request
4. If all goes well the HTTP status returned is 200 OK
5. The return parameter is of type HttpResponseMessage. We are only returning the status not the content.
6. Is not needed to return any Location as in the previous example as know it already. The same comes with the content.

Let’s see this visually:

Posting an update to an existing product will look like this. (Note that the Name of the product changed to be “Monitor”).

in case we try to update a non-existing product. Notice in the address bar, we are trying to update a product with the id = 11 that doesn’t exists. In that case we are returning HTTP status of 404 Not found.

DELETE

To delete an already existing object we need to pass only the actual ID, as defined in the code below:

// DELETE api/product/5
public HttpResponseMessage Delete(int id)
{
    Product product = repository.GetProduct(id);

    if (product == null)
    {
        return Request.CreateResponse(HttpStatusCode.NotFound);
    }

    try
    {
        repository.Delete(id);
    }
    catch (Exception exc)
    {
        return Request.CreateResponse(HttpStatusCode.BadRequest);
    }

    return Request.CreateResponse(HttpStatusCode.OK, product);
}

Note the following:
1. If product we want to delete is not there we return 404 Not found
2. If there is an exception we raise Bad Request
3. In case everything goes well, we return the 200 OK together with the object data, as the client would potentially need to display some information about the product itself.

Product deleted and the status returned as 200 OK.

When trying to delete a non existing resource the status 404 Not Found is returned.
Delete a non existing product.

Complete code

In order to make it easier for you, here is the full source code of the service.

public class ProductController : ApiController
{
    private readonly ProductContext repository = new ProductContext();

    // GET api/values
    public IEnumerable Get()
    {
        return repository.GetProducts();
    }

    // GET api/product/5
    public Product Get(int id)
    {
        Product product = repository.GetProduct(id);

        if (product == null)
        {
            throw new HttpResponseException(
            Request.CreateResponse(HttpStatusCode.NotFound));
        }
        else
        {
            return product;
        }
    }

    // POST api/product
    public HttpResponseMessage Post(Product product)
    {
        if (ModelState.IsValid)
        {
            // this will set the ID for instance...
            product = repository.AddProduct(product);

            var response = Request.CreateResponse(
                HttpStatusCode.Created, product);

            string uri = Url.Link("DefaultApi", new {id = product.Id});
            response.Headers.Location = new Uri(uri);
            return response;
        }
        else
        {
            return Request.CreateResponse(HttpStatusCode.BadRequest);
        }
    }

    // PUT api/product/5
    public HttpResponseMessage Put(int id, Product product)
    {
        if (ModelState.IsValid && id == product.Id)
        {
            var result = repository.Update(id, product);
            if (result == false)
            {
                return Request.CreateResponse(HttpStatusCode.NotFound);
            }
            return Request.CreateResponse(HttpStatusCode.OK);
        }
        else
        {
            return Request.CreateResponse(HttpStatusCode.BadRequest);
        }
    }

    // DELETE api/product/5
    public HttpResponseMessage Delete(int id)
    {
        Product product = repository.GetProduct(id);

        if (product == null)
        {
            return Request.CreateResponse(HttpStatusCode.NotFound);
        }

        try
        {
            repository.Delete(id);
        }
        catch (Exception exc)
        {
            return Request.CreateResponse(HttpStatusCode.BadRequest);
        }

        return Request.CreateResponse(HttpStatusCode.OK, product);
    }
}

Conclusion

ASP.NET Web API is a very versatile framework that allow us to create RESTful services in a very easy way without going through much pain when compared to the WCF configuration part for example.
The simplicity of HTTP statuses makes the development even more simple.

    Share...Tweet about this on TwitterShare on FacebookShare on Google+Share on StumbleUponShare on LinkedInPin on PinterestShare on TumblrShare on RedditDigg this

    I'm a Software Developer and Solution Architect interested in Software Development, Object-Oriented Design and Software Architecture all this especially bound to the Microsoft.NET platform.Feel free to contact me or know more in the about section

      38 Responses to “Building an ASP.NET Web Api RESTful service”

    1. Great

    2. one thing i want to ask..when we post data using Advance Rest Client.where will be the data stored?
      I mean the data we have entered in Advance Rest Client …will be stored in class file or else where..?

    3. it helps a lot!! thanks man!

    4. Very Useful code. Is there any way to catch Sql Exceptions and send back to RESTApi client?

    5. Zoran,

      I am a web forms, visual basic developer who is just starting to get into the MVC and C# world. I am trying to follow through your example but do not know how to create the product class exactly. Would you be able to explain that class a little more and possible send the full class code for that class?

      thank you!

    6. Hi Zoran,

      Can you please tell me how to convert the RESTful WEB API made in MVC4 into SOAP web service.

      • Hi,
        As far as I know there is nothing that can automatically convert your REST service into a SOAP web service.
        ASP.NET Web API doesn’t support SOAP so for this you must use WCF framework.

        Obviously, I don’t know the context of your project, but the steps I would follow are:
        1) Extract the business logic of your REST services. So, database connections, data manipulation, etc… to be placed into a separate library
        2) Start creating WCF Services and call the library created in the step 1)

        in this way you can share the code between WCF and REST services (if you need both of them).

        Another alternative would be to use ServiceStack framework, and move toward REST/SOAP based services without having to write individually the different types of services. For the SOAP support you can find more info here: https://github.com/ServiceStack/ServiceStack/wiki/SOAP-support

        Let me know…

    7. Hi Zoran,

      When i run your project ‘out of the box’ from VS 2012 – get the following error:

      “HTTP Error 403.14 – Forbidden” – “A default document is not configured for the requested URL, and directory browsing is not enabled on the server.”

      • I tried it out and I got the same error. So, you made me worry, as I wrote this article a while ago 🙂
        Actually, this is simply because there is no default value in the VS 2012 web service that would point to api/product.
        However, simply change the URL in the browser to http://localhost:34133/api/product and you will get the result 🙂

        Cheers,
        Zoran

    8. Thanks for that tutorial – reading yours, i found the bug in my own code 🙂

    9. Hi Zoran, Thanks for the post, i implemented it using Entity framework with an SQL database and it works like a shine, i just was wondering how it goes in real world when a user sends data in the post method when i inserted them in the raw input ?
      Thanks

      • Hi Zied,
        I guess you front end is a Asp.NET or Asp.NET MVC, or in any case it’s a web front end.
        In that case you can create a simple form where the user will fill all the information you need, and then you either post the content of the form to your service, or you can prepare your data, before sending them to the server, by using Javascript. I suggest you use JQuery as it is very versatile and useful.
        Here you have some examples of how to do that
        http://api.jquery.com/jQuery.post/

        I hope it helps.
        If you find a good solution, please post it here 🙂 for our knowledge.

        Zoran

        • Hello, in fact the action is very simple, using Rest service in the final application (inetgrating RestSharp) will give users options to add parameters and we will have smthing like this

          RestRequest request = new RestRequest();

          request.Method = Method.POST;

          request.AddParameter(“parametername”,”Data”);
          can’t beleive how i forgot that!
          i have an other question about the Put Method, i tested and it works but values doesn’t change !! any idea please?
          Thanks

    10. Thanks a lot for this article.
      Could you please explain why you use POST to create a new product and not PUT as you stated in “Creates a Resource. Use PUT if you are sending the full content of the specified resource (URL).”

      • Hi Ron,
        Thanks for your comment. Actually the PUT vs POST causes a lot of confusion.
        In reality you could use both for Creation and Update, it just depends how you want to use it, based on the URI to which one are you Posting or Putting.

        I think that this article contains a good answer to your question:
        http://stackoverflow.com/questions/630453/put-vs-post-in-rest

        • Hi Zoran,
          thanks for this tuto, i followed it and it works like shine with Entity Framework, i just wonderring in the post mode how the user can send data in the real world, for my part i created the service and passed the data in the input Raw to test it but when it comes to a simple user how will he pass parameters to Insert them ?
          Thanks Again 🙂

    11. Great.
      At the beginning you say that PUT:
      “Creates a Resource. Use PUT if you are sending the full content of the specified resource (URL).”
      But you use POST to create a product in the code example.
      Can you explain this please? Thanks a lot 🙂

    12. Thanks for tutorial. Is it possible to put product ID as attribute, so that xml output was ?

    13. Thanks Zoran for taking time to write this wonderful blog!!!

    14. how to achieve security with restful api in .net

    15. one thing i want to ask..when we post data using Advance Rest Client.where will be the data stored?
      I mean the data we have entered in Advance Rest Client …will be stored in class file or else where..?

      • Hi Darshan,
        I am not quite sure if I understood your question. Advanced Rest Client is just a client application that enables to post JSON or XML to a RESTful service, nothing more. So, that data is not “saved” anywhere really but just transmitted to the service. The RESTful service, before receiving the JSON data, through some filters will receive the deserialized JSON/XML object, for which one obviously you would need to have a class.
        If you have perhaps a more specific question I will be happy to try to help you.

    16. It’s really helpful.
      Thanks a lot!!!!!!

    17. Hi Zoran,

      i am getting below error:

      An error has occurred.

      The ‘ObjectContent`1’ type failed to serialize the response body for content type ‘application/xml; charset=utf-8’.

      System.InvalidOperationException

      An error has occurred.

      The operation cannot be completed because the DbContext has been disposed.

      System.InvalidOperationException

      at System.Data.Entity.Internal.InternalContext.CheckContextNotDisposed() at System.Data.Entity.Internal.LazyInternalContext.InitializeContext() at System.Data.Entity.Internal.InternalContext.Initialize() at System.Data.Entity.Internal.Linq.InternalQuery`1.GetEnumerator() at System.Data.Entity.Infrastructure.DbQuery`1.System.Collections.Generic.IEnumerable.GetEnumerator() at WriteArrayOfLeadToXml(XmlWriterDelegator , Object , XmlObjectSerializerWriteContext , CollectionDataContract ) at System.Runtime.Serialization.CollectionDataContract.WriteXmlValue(XmlWriterDelegator xmlWriter, Object obj, XmlObjectSerializerWriteContext context) at System.Runtime.Serialization.XmlObjectSerializerWriteContext.WriteDataContractValue(DataContract dataContract, XmlWriterDelegator xmlWriter, Object obj, RuntimeTypeHandle declaredTypeHandle) at System.Runtime.Serialization.XmlObjectSerializerWriteContext.SerializeAndVerifyType(DataContract dataContract, XmlWriterDelegator xmlWriter, Object obj, Boolean verifyKnownType, RuntimeTypeHandle declaredTypeHandle, Type declaredType) at System.Runtime.Serialization.XmlObjectSerializerWriteContext.SerializeWithXsiTypeAtTopLevel(DataContract dataContract, XmlWriterDelegator xmlWriter, Object obj, RuntimeTypeHandle originalDeclaredTypeHandle, Type graphType) at System.Runtime.Serialization.DataContractSerializer.InternalWriteObjectContent(XmlWriterDelegator writer, Object graph, DataContractResolver dataContractResolver) at System.Runtime.Serialization.DataContractSerializer.InternalWriteObject(XmlWriterDelegator writer, Object graph, DataContractResolver dataContractResolver) at System.Runtime.Serialization.XmlObjectSerializer.WriteObjectHandleExceptions(XmlWriterDelegator writer, Object graph, DataContractResolver dataContractResolver) at System.Runtime.Serialization.DataContractSerializer.WriteObject(XmlWriter writer, Object graph) at System.Net.Http.Formatting.XmlMediaTypeFormatter.c__DisplayClass7.b__6() at System.Threading.Tasks.TaskHelpers.RunSynchronously(Action action, CancellationToken token)

      Please , correct me , if i miss anything.

      Thanks.

    18. This is very helpful!

    19. Thanks very helpful!

    20. I have downloaded the code and run it. I can enter a uri and run the app and get results bun I am unable to get the form in this example. What am I doing wrong?

    21. That’s exactly the problem I’m having. I’m new to Web API’s, Ioc and DI and I’m having difficulty combining it all into one solution. There’s a lot of examples of IoC and DI OR Web API’s, but nothing with a solid architecture (i.e. decoupled code) combining them all.

      Anyways, thank you so much for your time!

    22. Would you be able to provide sample code with an actual database please? I’ve been really struggling with the full concept. Thank you!

      • Hi Jon,
        For reason of brevity of the article, I was only pointing out the changes and what should be done in order to create a service, without actually going deeper into the database connectivity.
        If you check the source code (the example project that you may download) there is a class called ProductContext where I am actually adding in memory some example data, just for the purpose of trying out the solution.
        Depending on the database and the underlying technology for accessing database you are using the “solution” would potentially change. So there is no one single answer.

        As a potential solution to the existing example
        1) You may simply add the connection to the database directly in the ProductContext class and query your database from there. Just to see how it works.

        But in an real world example I would use some architecturally more interesting patterns like:
        – Repository Pattern (each repository would have single responsibility and hold access to the db for a specific object),
        – Interface segregation: You don’t want to couple your Service with the database logic implementation, so the coupling between objects should be done through interfaces.
        – Inversion Of Control : To actually inject the implementation object at run time.

        Try checking this forum for further info about Setting up web api to pull data from a database using Entity Framework in case you are using SQL Server and want to use Entity Framework.

        When i have a bit more time, which I never really have 🙂 I will try to extend this solution with what said above.

    Leave a Reply

    hovenga146@mailxu.com mapes@mailxu.com