In my previous post I wrote about first steps in creating Rest-full API by using ApiController. Now it`s time to make next step and go a little bit dipper inside web services created in MVC. In this post I want to describe two very important aspect:
- creating a real life scenario for web service implementation of POCO entity
- extend presented scenario and make it asynchronous
To complete this tutorial one more class is needed. This class is a simple fake of some database which is wrapper around a very few collections and allow all CRUD operation. Moreover the implementation of this fake database uses a singleton design pattern to prevent creating instance of it each time and maintain state between web service calls.
Code Snippet
- /// <summary>
- /// Represents a fake database.
- /// </summary>
- public sealed class FakeDbContext
- {
- private static volatile FakeDbContext instance;
- private static object syncRoot = new Object();
- private FakeDbContext()
- {
- this.Users = new List<User>();
- this.Dictionary = new Dictionary<string, string>();
- }
- public static FakeDbContext Instance
- {
- get
- {
- if (instance == null)
- {
- lock (syncRoot)
- {
- if (instance == null)
- instance = new FakeDbContext();
- }
- }
- return instance;
- }
- }
- public List<User> Users { get; set; }
- public Dictionary<string, string> Dictionary { get; set; }
- }
The real life scenario that we want to implement is a simple web service which expose all CRUD operation and of course it`s base on REST. In the following class each API functions return the same type HttpResponseMessage which represent a standard HTTP response. This type contains two important properties: StatusCode - which represent a HTTP response status code and Content - which store body of the response if any. The the easiest to produce a HttpResponseMessage is calling one of many build-in functions which are responsible for creating a fully qualified response based on several input parameter:
- Request.CreateResponse - the simplest method for returning any type of response with or without content
- Request.CreateResponse<T> - create a success response with content of T type
- Request.CreateErrorResponse - create a error response and requires to specify HTTP code status and exception
Code Snippet
- /// <summary>
- /// Represent a controller for managing <see cref="User"/>.
- /// </summary>
- public class UserController : ApiController
- {
- public UserController()
- {
- if (!FakeDbContext.Instance.Users.Any())
- {
- FakeDbContext.Instance.Users = new List<User>()
- {
- new User(){ Id = 1, FirstName = "Roberto", LastName="Carlos", Email="robi_carlo@gmail.com"},
- new User(){ Id = 2, FirstName = "Zinédine", LastName="Zidane", Email="zizu@live.com"},
- new User(){ Id = 2, FirstName = "Peter", LastName="Schmeichel", Email="scheisse@yahoo.com"},
- };
- }
- }
- // GET api/person
- [HttpGet]
- public HttpResponseMessage Get()
- {
- return Request.CreateResponse<ReadOnlyCollection<User>>(HttpStatusCode.OK, FakeDbContext.Instance.Users.AsReadOnly());
- }
- // GET api/person/5
- [HttpGet]
- public HttpResponseMessage Get(int id)
- {
- var resultUser = FakeDbContext.Instance.Users.FirstOrDefault(u => u.Id == id);
- if (resultUser == null)
- {
- return Request.CreateErrorResponse(HttpStatusCode.NotFound, "User dones`t exists.");
- }
- return Request.CreateResponse<User>(HttpStatusCode.OK, resultUser);
- }
- // POST api/person
- [HttpPost]
- public HttpResponseMessage Post(User value)
- {
- if (value == null)
- {
- return Request.CreateErrorResponse(HttpStatusCode.BadRequest, "Null User object.");
- }
- // Checking user already exists in a list.
- if (FakeDbContext.Instance.Users.Contains(value))
- {
- return Request.CreateErrorResponse(HttpStatusCode.Conflict, "User already exists.");
- }
- else
- {
- FakeDbContext.Instance.Users.Add(value);
- }
- return Request.CreateResponse(HttpStatusCode.Created);
- }
- // PUT api/person/5
- [HttpPut]
- public HttpResponseMessage Put(int id, [FromBody] User value)
- {
- if (value == null)
- {
- return Request.CreateErrorResponse(HttpStatusCode.BadRequest, "Null User object.");
- }
- if (!FakeDbContext.Instance.Users.Any(u => u.Id == id))
- {
- return Request.CreateErrorResponse(HttpStatusCode.NotFound, "User dones`t exists.");
- }
- else
- {
- FakeDbContext.Instance.Users.Remove(value);
- FakeDbContext.Instance.Users.Add(value);
- }
- return Request.CreateResponse(HttpStatusCode.OK);
- }
- // DELETE api/person/5
- [HttpDelete]
- public HttpResponseMessage Delete(int id)
- {
- var personToDelete = FakeDbContext.Instance.Users.FirstOrDefault(u => u.Id == id);
- if (personToDelete == null)
- {
- return Request.CreateErrorResponse(HttpStatusCode.NotFound, "User dones`t exists.");
- }
- else
- {
- FakeDbContext.Instance.Users.Remove(personToDelete);
- }
- return Request.CreateResponse(HttpStatusCode.OK);
- }
- }
Now our service is ready to use and we run it and we can call each GET, POST, PUT and DELETE function by using any of HTTP Client.
![]() |
Picture 1. Calling GET and POST API from test HTTP Client. |
Thank you.