C++ REST SDK (Casablanca) included with VS 2013

If you have the VS 2013 preview, then setting up the C++ REST SDK is easy. Right-click on the project in Solution Explorer, bring up the References dialog, select Add New Reference, select Extensions, and pick the C++ REST Extension SDK for Windows Store apps. That’s all. No need to separately setup include and lib paths. In the preview release, the files are in C:\Program Files (x86)\Microsoft SDKs\Microsoft Cpp REST SDK for Visual Studio 2013 Preview\SDK. This would quite likely change in the RTM version.

Even if you don’t have VS 2013, Casablanca is now available as a NuGet package. So you can install it from there as well, although in that case it gets installed as a project specific package.

Casablanca – showing progress for an HTTP download

The current release of Casablanca does not support progress reporting when reading from an HTTP stream, you only know when it’s completed – but, you can read chunk by chunk and get a percentage based on the total size that you can get off the header. Here’s a code snippet that shows one way of doing this with PPL tasks. It recursively calls the Repeat function until there’s nothing left to read, and the then() code in the original call is executed. So you still get a completed event while also being able to report progress. The code snippet does not do anything with the data, it just shows a percentage.

concurrency::task<void> Repeat(
  istream bodyStream, size_t chunkSize, 
  size_t lenRead, size_t contentLength)
{
	container_buffer<std::string> buffer;

	return concurrency::create_task(
    [=] { return bodyStream.read(buffer, chunkSize).get(); })
		.then([=](int bytesRead)
	{
		if(bytesRead > 0)
		{
			std::wcout << (lenRead + bytesRead) * 100 / contentLength 
                 << L"% downloaded"  << std::endl;
			return Repeat(bodyStream, chunkSize, lenRead + bytesRead, contentLength);
		}

		return concurrency::create_task([]{});
	});
}

// . . .

http_client client(L"http://www.codeproject.com");

client.request(methods::GET).then([](http_response response)
{
  if(response.status_code() == status_codes::OK)
  {
    auto bodyStream = response.body();		

    size_t contentLength = response.headers().content_length();
    std::wcout << L"Content length: " << contentLength << std::endl;            

    Repeat(bodyStream, 8192, 0, contentLength).then([]
    {
      std::wcout << L"Completed." << std::endl;            
    });
  }
});

Here’s some sample output:

Content length: 79025
3% downloaded
13% downloaded
17% downloaded
27% downloaded
31% downloaded
41% downloaded
42% downloaded
52% downloaded
58% downloaded
68% downloaded
68% downloaded
79% downloaded
79% downloaded
89% downloaded
91% downloaded
100% downloaded
Completed.

I am not a PPL expert so if you notice anything quirky about this, feel free to comment on it. Thanks.

Casablanca – JSON POST code snippet

Continuing on with Casablance, here’s a code snippet that shows how to POST JSON data to a web server.

json::value postData;
postData[L"name"] = json::value::string(L"Joe Smith");
postData[L"sport"] = json::value::string(L"Baseball");

http_client client(L"http://localhost:5540/api/values");

client.request(methods::POST, L"", postData.to_string().c_str(), 
  L"application/json").then([](http_response response)
{
  std::wcout <<  response.status_code() << std::endl;

  if(response.status_code() == status_codes::OK)
  {
    auto body = response.extract_string();		

    std::wcout << body.get().c_str();
  }
});

C++ does not have reflection, so unlike with .NET, you need to manually create the JSON from an object structure (which may seem like too much work if you’ve used JSON libraries in C# where the JSON is easily auto-generated using reflection). But it should not be too difficult to come up with some helper classes/methods that’ll make this easier for you.

Casablanca code snippets – getting and parsing JSON data

Casablanca is very easy to get started with if you’ve used PPL tasks before, and even if you haven’t it’s still fairly straightforward to use. Here’s an example showing how easy it is to make a GET request to a webserver and to extract the response as a string.

http_client client(L"http://localhost:5540/api/values");

client.request(methods::GET).then([](http_response response)
{
  if(response.status_code() == status_codes::OK)
  {
    auto body = response.extract_string().get();		
    std::wcout << body;
  }
});

The test service I was playing with returned JSON data, and Casablanca has classes to handle JSON too.

[
   {
      "Id":1,
      "Name":"Nish",
      "Sport":"Tennis"
   },
   {
      "Id":2,
      "Name":"Andrew",
      "Sport":"Baseball"
   }
]

Here’s an example showing how the JSON data can be parsed out.

http_client client(L"http://localhost:5540/api/values");

client.request(methods::GET).then([](http_response response)
{
  if(response.status_code() == status_codes::OK)
  {
    response.extract_json().then([](json::value jsonValue)
    {
      for(auto iterArray = jsonValue.cbegin(); iterArray != jsonValue.cend(); ++iterArray)
      {
        const json::value &arrayValue = iterArray->second;

        for(auto iterInner = arrayValue.cbegin(); iterInner != arrayValue.cend(); ++iterInner)
        {
          const json::value &propertyName = iterInner->first;
          const json::value &propertyValue = iterInner->second;

          std::wcout 
            << L"Property: " << propertyName.as_string() 
            << L", Value: " << propertyValue.to_string() 
            << std::endl;

        }		

        std::wcout << std::endl;
      }
    });
  }
});

I hope to publish more Casablanca code samples/snippets on this blog, just FYI.

Setting VC++ up to use Casablanca

Once you’ve installed Casablanca, you’ll need to add the required include/lib folders to your VC++ projects. I took the same approach used by the sample projects.

Open Project Properties / Configuration Properties / C/C++ / General and add the following entry to the Additional Include Directories. (note: line breaks added for formatting)

$([MSBuild]::GetRegistryValue(
`HKEY_LOCAL_MACHINE\Software\Microsoft\Casablanca\OpenSourceRelease\110\SDK`, 
`InstallDir`))\include

Open Project Properties / Configuration Properties / Linker / General and add the following entry to the Additional Library Directories (separate ones for Debug and Release configs). (note: line breaks added for formatting)

$([MSBuild]::GetRegistryValue(
`HKEY_LOCAL_MACHINE\Software\Microsoft\Casablanca\OpenSourceRelease\110\SDK`,
`InstallDir`))\lib\x86\Debug\
$([MSBuild]::GetRegistryValue(
`HKEY_LOCAL_MACHINE\Software\Microsoft\Casablanca\OpenSourceRelease\110\SDK`,
`InstallDir`))\lib\x86\Release\

Now add casablanca110.lib to the Linker / Input / Additional Dependencies.

You’re all set at this point.