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.

Mapping a Visual C++ filter to a physical folder

There is one annoyance in Visual C++ (2010/2012) for people used to C#’s solution/project folder behavior where a folder in the project maps to a namespace, and any files/classes you add to that folder are physically added to an equivalent subfolder in the file system. Unfortunately, with VC++, the closest equivalent is a project filter which is not a physical folder. There are some very obvious disadvantages to this approach.

  • You cannot have the same filename under multiple filters. Example, if you have base.h under the data filter and you want to add base.h to the view filter, you cannot, since they are both in the root folder.
  • A second issue is that when you #include files, you cannot use the filter name in the path, and have to use the physical path which may often be confusing.
  • File organization also gets messy because all the files get created in one single folder.

A workaround that I use is to do this.

  • I create a physical sub-folder inside the project folder.
  • I then select “show all files” in the solution explorer and manually include this folder
  • Then, I create a filter of the same name (as the subfolder)
  • I then add new files/classes to this folder, and also drag/drop the file into the filter in solution explorer

Obviously, this is a bit of a hassle, but it’s still the simplest approach given the way they chose to make filters work. You can save one step by selecting the right folder when adding a file/class to a filter.

FilterFileLocation

I hope the next version of VC++ will emulate the more intuitive and convenient behavior available for C# projects.