How to consume ASP.NET Web API RC with RestSharp?

As I mentioned in my blog before that ASP.NET Web API will be the next generation of WCF for creating RESTful web service which can be consumed by any platforms or devices supporting HTTP protocol. It is a part of ASP.NET MVC 4 , can be installed on Visual Studio 2010 or Visual Studio 2012 and is currently on Release Candidate version. It’s first time that I try a RC product in my software and I had really a lot of troubles:
– There are breaking changes from Beta version to RC version which causes a lot of things not work anymore.
– The Castle Windsor (an Inversion of Control container) runs unstably with ASP.NET Web Server because of his error “Could not load file or assembly…” and I do have to stop debugging, stop ASP.NET Web Server and start again each time when an exception was thrown or when I stop debugging at any position in source code.
– The Inversion of Control container must be attached with new code when changing from Beta version to RC version.
– Lack of documentation.

I think I should end with my complaints now and go back to the topics before I go too far with them :). So, ASP.NET Web API allows us to create a RESTful service which can be called through HTTP protocol, which means that you can call it by simply entering a URL like this in you web browser http://servicesurl.com/api/resources and you’ll get a result back directly on your web browser. For example, when you create a Web API service project, there is a sample resource called “Value” and you can call it directly in your web browser

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

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

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

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

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

Call RESTful webservice from browser

If you use Fiddler to inspect the HTTP request, you’ll see that Chrome requires the content as default under “text/html,application/xhtml+xml,application/xml” format and therefore we get our object IEnumerable as an array of XML element.

Media types when calling RESTful service from Chrome

The media type determines how Web API serializes and deserializes the HTTP message body. A media type (MIME type) describes the format of a piece of data as well as the format of the HTTP message body. The syntax to define a MIME type consists of two strings, a type and a subtype, such as: text/html, application/xhtml+xml,application/xml, image/png, application/json. If the Content-Type header was set by a specified MIME type, the service will try to parse the result according to this format and send it back. To better understand it, now we use Fiddler to call the URL above again, but this time we require the content as “application/json”, we’ll receive our object as a JSON object back.

Call RESTful service with json

Result of RESTful in Json

There is built-in support for XML, JSON, and form-urlencoded data in Web API, and you can support additional media types by writing your own media formatter. We’re now finished with the most simple example of Web API. However in fact for each resource, we often need multiple GET,POST,PUT and DELETE. For example, we have a “Product” resource, we would like to get all products, products by id, products by category or products by price or whatever… so if we call implicit our resources only with HTTP action (GET,POST,PUT and DELETE) and parameters like before, we won’t be able to make multiple HTTP actions work because Web API can’t distinguish between to function Get(Int productId) and Get(Int category). Moreover it’s very difficult to maintain the code of client where the only difference between the actions is the number of parameters and their types.

Therefore in class RouteConfig, I would like to change MapHttpRoute of DefaultApi to use action in his template

routes.MapHttpRoute(
	name: "DefaultApi",
	routeTemplate: "api/{controller}/{action}/{id}",
	defaults: new { id = RouteParameter.Optional }
);

And from now on, if my Products resource defined like listing below

public class ProductsController : ApiController
{
	private IProductRepository productRepository;

	public ProductsController(IProductRepository productRepository)
	{
		this.productRepository = productRepository;
	}

	// GET api/products
	[HttpGet]
	public IQueryable<Product> GetAll()
	{
		return productRepository.ReadAll();
	}
}

I can call data from client by giving explicit the action name

public List<Product> GetAll()
{
	var request = new RestRequest("products/GetAll", Method.GET);
	return restClient.Execute<List<Product>>(request).Data;
}

And if I would like to support more Get for Products resource I just simply define another GET in ProductsController with different name.

 public class ProductsController : ApiController
{
	...

	// GET api/products/5
	[HttpGet]
	public Product Get(Guid productId)
	{
		Product product = productRepository.Read(productId);
		if (product == null)
			throw new HttpResponseException(new HttpResponseMessage(HttpStatusCode.NotFound));
		return product;
	}

	
	...
}

This GET action will receive a parameter of Id, ask the repository for the product of that Id and give Product back. What beautiful is that you can give parameter as a Guid or a string. In case that you give a Guid, RestSharp will serialize it to string and call the service with this value. The Web API, on his site, will deserialize this string back to Guid object.

public Product Get(Guid productId)
{
	var request = new RestRequest("products/Get", Method.GET);
	request.AddParameter("productId", productId);
	return restClient.Execute<Product>(request).Data;
}

public Product Get(string productId)
{
	var request = new RestRequest("products/Get", Method.GET);
	request.AddParameter("productId", productId);
	return restClient.Execute<Product>(request).Data;
}

In listing above, you see that I call same action but with parameters of different types (Guid and string). If you want another GET with Enum parameter, it works too.

public class ProductsController : ApiController
{
	...
	[HttpGet]
	public IQueryable<Product> GetByCategoryAndInitial(ProductCategories category, string initial)
	{
		return productRepository.ReadAll().Where(x => (ProductCategories)x.Category == category &amp;&amp; x.Name.StartsWith(initial)).AsQueryable();
	}
	...
}

and on client’s site

public List<Product> GetByCategoryAndInitial(ProductCategories category, string initial)
{
	var request = new RestRequest("products/GetByCategoryAndInitial", Method.GET);
	request.AddParameter("category", category);
	request.AddParameter("initial", initial);
	return restClient.Execute<List<Product>>(request).Data;
}

The miracle why it works with Enum types is pretty simple. RestSharp will serialize enum to int and Web API will deserialize it again back to Enum. It sounds great,doesn’t it? It seems to be that we can transfer any datatype that we want. But the reality is hard and the answer is no. We can’t use any datatype as we want. I add one more GET for Products resource to demonstrate the problem.

public class ProductsController : ApiController
{
	...
	[HttpGet]
	public IQueryable<Product> GetByCategoryAndStartPriceDouble(ProductCategories category, double startPrice)
	{
		return productRepository.ReadAll().Where(x => (ProductCategories)x.Category == category &amp;&amp; x.Price >= (decimal)startPrice).AsQueryable();
	}
	...
}

Now if we call the action above with parameter of double

public List<Product> GetByCategoryAndStartPriceDouble(ProductCategories category, double startPrice)
{
	var request = new RestRequest("products/GetByCategoryAndStartPriceDouble", Method.GET);
	request.AddParameter("category", category);
	request.AddParameter("startPrice", startPrice);
	return restClient.Execute<List<Product>>(request).Data;
}

We will get exception

“The parameters dictionary contains a null entry for parameter ‘startPrice’ of non-nullable type ‘System.Double’ for method ‘System.Linq.IQueryable`1[Asp.net_Web_Api_and_RestSharp.Contract.Models.Product] GetByCategoryAndStartPriceDouble(Asp.net_Web_Api_and_RestSharp.Contract.Models.ProductCategories, Double)’ in ‘Asp.net_Web_Api_and_RestSharp.Controllers.ProductsController’. An optional parameter must be a reference type, a nullable type, or be declared as an optional parameter.”

The reason is our value “startPrice” is UrlEncoded which mean the decimal separator will also be UrlEncoded and Uri turns to be like this

http://localhost:57843/api/products/GetByCategoryAndStartPriceDouble?category=GroceryHealthBeauty&startPrice=20%2C12

The value 20.12 was converted to 20%2C12 depending on culture and therefore the Web API can’t recognize the double value anymore. To solve this problem with decimal separator (double, decimal,float…), we will give a string of that value instead.

public List<Product> GetByCategoryAndStartPriceString(ProductCategories category, double startPrice)
{
	var request = new RestRequest("products/GetByCategoryAndStartPriceDouble", Method.GET);
	request.AddParameter("category", category);
	request.AddParameter("startPrice", startPrice.ToString(CultureInfo.InvariantCulture));
	return restClient.Execute<List<Product>>(request).Data;
}

Now we already know how to make a multiple-GET service with simple type (A “simple type” includes: primitives, TimeSpan, DateTime, Guid, Decimal, String, or something with a TypeConverter that converts from strings.(From Mike Stall)). Let’s try with another HTTP action and more complex object.

public class ProductsController : ApiController
{
	...
	// POST api/products
	[HttpPost]
	public Product Post(Product product)
	{
		return productRepository.Create(product);
	}
	...
}

Here we have an action which only accepts HTTP post and one parameter of complex type. How does Web API bind this kind of parameters? In deed there are 2 techniques for binding parameters: Model Binding (ModelBindingParameterBinder) and Formatter (FormatterParameterBinder). And what important in RC version is, WebAPI uses model binding to read from the query string and Formatters to read from the body. The model binding is what we did above, we give the parameters in URL and call the web service with them and remember, it works only with simple types. For complex type like the POST above, we must use Formatters to deserialize data from HTTP body. The client should call the service like this listing

public Product Post(Product product)
{
	var request = new RestRequest("products/Post", Method.POST);
	request.RequestFormat = DataFormat.Json;
	request.AddBody(product);
	return restClient.Execute<Product>(request).Data;
}

In listing above, I tell that “Hello Web API, I am transferring a complex object in my HTTP body and I use JSON to serialize it”. The Web API when receiving this HTTP request, should look at HTTP body, pull the object out, use JSON formatters (default is JSON.Net) to deserialize him back to CLR one and we’ll get the information we need at service site. It sounds simple. Now you maybe ask in case that you want to pass one simple type and one complex type. You can’t just create another object just to transfer the message. What should you do now? Then just follow the rules of Web API, the simple types should be given in URL and the body contains the complex one. For example, I have this action

public class ProductsController : ApiController
{
	...
	// PUT api/products/5
	[HttpPut]
	public bool Put(string productId, Product product)
	{
		return productRepository.Update(product);
	}
	....
}

He is waiting for a Guid (simple type) and a Product (complex type) as his parameters and we call it like listing below

public bool PutWithGuid(Guid productId, Product product)
{
	bool result = false;
	var request = new RestRequest("products/PutWithGuid/?productId={productId}", Method.PUT);
	request.RequestFormat = DataFormat.Json;
	request.AddParameter("productId", productId.ToString(), ParameterType.UrlSegment);
	request.AddBody(product);
	Boolean.TryParse(restClient.Execute(request).Content, out result);
	return result;
}

All simple types were given through UrlSegment and the others should be in body part, that’s the rules. If you have many complex objects, you don’t have other choice you must “combine” all of them into one complex object and add it to body because the HTTP body can contain “only one” object to be deserializable at the service site. In case that you want to pass many parameters with simple types to service, just create each one as a UrlSegment.

For example, we have an action

[HttpPut]
public bool PutWithProperties(Guid productId, int category, string name, int price)
{
	Product product = productRepository.ReadAll().Where(x => x.Id == productId).FirstOrDefault();
	if (product != null)
	{
		product.Category = category;
		product.Name = name;
		product.Price = (decimal)price;
		return productRepository.Update(product);
	}
	else
		return false;
}

and on the client

public bool PutWithProperties(Guid productId, ProductCategories category, string name, int price)
{
	bool result = false;
	var request = new RestRequest("products/PutWithProperties/?productId={productId}&category={category}&name={name}&price={price}", Method.PUT);
	request.RequestFormat = DataFormat.Json;
	request.AddParameter("productId", productId.ToString(), ParameterType.UrlSegment);
	request.AddParameter("category", (int)category, ParameterType.UrlSegment);
	request.AddParameter("name", name, ParameterType.UrlSegment);
	request.AddParameter("price", price, ParameterType.UrlSegment);
	Boolean.TryParse(restClient.Execute(request).Content, out result);
	return result;
}

So far so good, it’s pretty simple to consume a Web API service if you know how it works and what he requires from you. However because the product is still in Release Candidate version and not well documented therefore it’s really complicated to figure how it works. Just one more problem I would like to discuss is when we activate the action name in URL, we don’t have a RESTful webservice anymore but we have now a RPC. A RESTful API exposes its data as resources at URIs that clients interact with via HTTP methods like GET and POST (or verbs). On the other hand, remote procedure call (RPC) refers an API style where endpoints perform arbitrary actions, not necessarily tied to a particular resource. I intend to show how multiple GET/POST/PUT works therefore I use action name to emphasize the idea but if you don’t want to use RPC, just remove action name in route and it’ll work like REST.

So I hope that this post will help you to have an easy start-up with Web API. The source code can be downloaded here “Asp.net Web Api and RestSharp

UPDATE 08.08.2012
If you have null parameter at the controller, maybe RestSharp doesn’t support kind of data. For example I had a property with type of Dictionary> and I get always value null at controller because the type is not supported. For more information please read here https://github.com/restsharp/RestSharp/wiki/Deserialization

4 thoughts on “How to consume ASP.NET Web API RC with RestSharp?”

Leave a Reply

Your email address will not be published. Required fields are marked *