Web API alternative – self hosting HTTP services in native C++ code

Β· 1407 words Β· 7 minutes to read

On this blog, I’ve been focusing pretty much exclusively on ASP.NET Web API, but today let’s step outside .NET, and explore how you could host RESTful HTTP services directly from the native unmanaged C++ code - and I hope, this is going to be a very interesting journey, especially as C++ is so much more efficient than any managed language.

If you haven’t done C++ before, or haven’t done any in years, don’t dread, modern C++ is quite different than what you might be used to of have heard of. Microsoft DevLabs and Niklas Gustafsson provide a terrific experimental library called [Casablanca][1], which is a C++ SDK aimed at creating modern HTTP services in native code.

More after the jump.

Getting started with Casablanca πŸ”—

You can grab the Casablanca SDK for Visual Studio 2012 from [here][2] and you can read up about the project [here][1].

The main strengths of Casablanca is that it provides C++ developers a number of wrappers around functionality that otherwise are very difficult to achieve with pure C-level coding:

  • self hosting a server using HTTP listeners
  • implementations of very unusual in C++ world, but common for .NET developers concepts like JSON, HTTP status codes, URI and so on
  • very powerful asynchronous model (and, yes, asynchrony in C++ is much more difficult than anything you might be used to in managed languages)
  • integration into Azure
  • very good actor programming model, derived from Erlang

Once you installed the SDK, we are ready to go.

Creating a self-hosted server in native C++ application πŸ”—

If you used ASP.NET Web API self hosting, or anything that implemented HTTP Listeners in C#, this should feel very familiar. We are going to create a C++ application and self host a server in there, and then interact with it from the browser.

Let’s start with creating a new app, C++, Win32 Console Application, the default wizard settings are fine. Now we need to add references to Casablanca. There a few ways to achieve this, but the quickest is to modify the project’s properties. Go to the properties and:

  • under VC++ Directories, add the entry for Executable Directories:
    $([MSBuild]::GetRegistryValue(`HKEY_CURRENT_USERSoftwareMicrosoftCasablanca110SDK`, `InstallDir`))binx86Debug;$(ExecutablePath)
  • under C/C++, add the entry for Additional Include Directories:
    $([MSBuild]::GetRegistryValue(`HKEY_CURRENT_USERSoftwareMicrosoftCasablanca110SDK`, `InstallDir`))include
  • under Linker, add the entry for Additional Library Directories:
    $([MSBuild]::GetRegistryValue(`HKEY_CURRENT_USERSoftwareMicrosoftCasablanca110SDK`, `InstallDir`))libx86Debug
  • under Linker > Input add the following entry for Additional Dependencies:
    casablanca110.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib; comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib; uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)

And off we can go!

We will be self hosting inside our app using http_listener.h, so sure enough, we need to import this header file. You might do that in the stdafx.h or however you like to organize you dependencies.

To self host we need:

  • a localhost URI + port for our HTTP server to listen at,
  • astreambuf.h, iostream from Standard Library and the aforementioned http_listener.h
  • a lambda that will be used to provide a response to an incoming HTTP request, more on that later
// NativeHttpServer.cpp : Defines the entry point for the console application.  
//  
#include "stdafx.h"  
#include <iostream>  
#include "astreambuf.h"

using namespace http;  
using namespace http::listener;

int \_tmain(int argc, \_TCHAR* argv[])  
{  
uri_builder uri(L"http://localhost:123/");  
http_listener listener;

listener = http\_listener::create(uri.to\_uri(),[](http_request msg){  
msg.reply(http::status_codes::OK, U("I'm hosted in native C++!"));  
});

listener.listen([]() { fgetc(stdin); }).wait();  
return 0;  
}  

Again, if you used Web API self host this looks awfully familiar. We start off by importing two Casablanca namespaces, and declare a localhost address. Then we pass it in the constructor of the http_listener. Additionally, we pass in a lambda - for providing a GET handler for incoming requests.

The constructor actually has some overloads and can take in 4 lambdas - for GET, PUT, POST and DELETE - but in this simple example we only handle GET.

At the end of this code bit, we simply tell the server to listen to any incoming requests until someone hits enter to close the application.

Before we run this app, you need to copy two files to the build folder (since the installation of the SDK will not modify your PATH settings):

  • casablanca110.dll
  • casablanca110.pdb

For debug builds you can copy these files from C:Program Files (x86)Microsoft Code Name Casablanca SDK for VS 2012SDKbinx86Debug to your Debug folder.

If we now run the application and point our browser to http://localhost:4999/ and voila:

[][3]

Self hosting from C++ working like a charm. Of course this example was very simple, so let’s add a little twist - and return and accept JSON.

RESTful service with C++ πŸ”—

Let’s add a simple class Person, which we will send down over the wire to the HTTP client as JSON and which we will accept in the POST method as client’s input (in JSON as well).

Header:

#pragma once  
class Person  
{  
public:  
std::string FirstName;  
std::string LastName;  
int Age;

Person(std::string first, std::string last, int age);  
~Person(void);  
};  

Implementation:

#include "stdafx.h"  
#include "Person.h"

Person::Person(std::string first, std::string last, int age) : FirstName(first), LastName(last), Age(age)  
{}

Person::~Person(void)  
{}  

Because we are going to convert this class to JSON, we need to add additional methods for handling to-JSON and from-JSON conversion. The to-JSON one can be invoked off an existing person pointer but the from-JSON will be static.

So in the Person.cpp we add:

http::json::value Person::ToJSON() const  
{  
http::json::value result = http::json::value::object();  
result[L"FirstName"] = http::json::value::string(utilities::conversions::to\_string\_t(FirstName));  
result[L"LastName"] = http::json::value::string(utilities::conversions::to\_string\_t(LastName));  
result[L"Age"] = http::json::value::number(Age);  
return result;  
}  

And in the header we add the definition and the static method:

http::json::value ToJSON() const;  
static Person FromJSON(http::json::value object)  
{  
const http::json::value &first = object[L"FirstName"];  
const http::json::value &last = object[L"LastName"];  
const http::json::value &age = object[L"Age"];

Person result(utilities::conversions::to\_utf8string(first.as\_string()), utilities::conversions::to\_utf8string(last.as\_string()), age.as_integer());  
return result;  
}  

We are using here the wonderful JSON functionalities provided by Casablanca - in this case, http::json::value. Notice that the JSON implementation requires csablanca::string_t, Casablanca’s version of string so we use utility functions to convert back and forth from std::string.

Now we can enhance our server a bit, by passing in lambdas to handle not just GET but other HTTP verbs as well:

int \_tmain(int argc, \_TCHAR* argv[])  
{  
uri_builder uri(L"http://localhost:4999/");  
http_listener listener;  
auto p = new Person("Filip","W",95);

listener = http\_listener::create(uri.to\_uri(),  
\[p\](http_request message)  
{  
std::cout << "Serving GET" << std::endl; message.reply(http::status_codes::OK, p->ToJSON());  
},  
\[p\](http_request message)  
{  
auto posted = p->FromJSON(message.extract_json().get());  
message.reply(http::status_codes::NoContent);  
std::cout << "Received a PUT of " << posted.FirstName << ", " << posted.LastName << ", " << posted.Age << std::endl; }, \[p\](http\_request message) { auto posted = p->FromJSON(message.extract\_json().get());  
std::cout << "Received a POST of " << posted.FirstName << ", " << posted.LastName << ", " << posted.Age << std::endl; message.reply(http::status\_codes::NoContent); }, \[p\](http\_request message) { message.reply(http::status_codes::NoContent); std::cout << "Deleting " << p->FirstName << std::endl; }); listener.listen([]() { fgetc(stdin); }).wait(); return 0; }
``` The order of lambdas is actually: GET, PUT, POST and DELETE. We don't do much here except serving an object on GET, accepting input on POST/PUT and respoding with relevant HTTP status code (such as "no content"). I am also logging the activities in the command line output to keep track of what's going on. If we run this application now, we can send all kinds of RESTful requests: **GET**:

[<img src="/images/2012/12/get.png" alt="" title="get" width="620" height="235" class="aligncenter size-full wp-image-700" srcset="/images/2012/12/get.png 917w, /images/2012/12/get-300x114.png 300w" sizes="(max-width: 620px) 100vw, 620px" />][4]

**POST**:

[<img src="/images/2012/12/post1.png" alt="" title="post" width="620" height="259" class="aligncenter size-full wp-image-704" srcset="/images/2012/12/post1.png 980w, /images/2012/12/post1-300x126.png 300w" sizes="(max-width: 620px) 100vw, 620px" />][5]

**PUT**:

[<img src="/images/2012/12/put.png" alt="" title="put" width="620" height="259" class="aligncenter size-full wp-image-702" />][6]

**DELETE**:

[<img src="/images/2012/12/delete.png" alt="" title="delete" width="620" height="257" class="aligncenter size-full wp-image-699" srcset="/images/2012/12/delete.png 972w, /images/2012/12/delete-300x124.png 300w" sizes="(max-width: 620px) 100vw, 620px" />][7]

How cool is that?

### Source code and summary

Of course the examples here are very simple, but hopefully you get the idea that actually self hosting in native C++ is a damn piece of cake with Casablanca. There are many other HTTP concepts that we didn't even touch on here, so if there is a need to go deeper, we can have more posts in the future πŸ™‚

You can apply pretty much all of your HTTP knowledge because Casablanca provides very nice (for C++ standards) model to work with all of the cornerstones of HTTP - response codes, headers, content types (nice JSON support) and such.

Of course it's still C++, so you better know what you are doing, but for high performance tools, this is a very, very viable option for providing a modern HTTP service and an great alternative to its managed language counterparts. And all I can say in the end, is "thanks, Niklas".

- Source code for the example is on [Github][8]

 [1]: http://msdn.microsoft.com/en-us/devlabs/casablanca
 [2]: http://go.microsoft.com/fwlink/?LinkId=249446&clcid=0x409
 [3]: /images/2012/12/simple_server.png
 [4]: /images/2012/12/get.png
 [5]: /images/2012/12/post1.png
 [6]: /images/2012/12/put.png
 [7]: /images/2012/12/delete.png
 [8]: https://github.com/filipw/sample-native-cplus-http-service

About


Hi! I'm Filip W., a software architect from ZΓΌrich πŸ‡¨πŸ‡­. I like Toronto Maple Leafs πŸ‡¨πŸ‡¦, Rancid and quantum computing. Oh, and I love the Lowlands 🏴󠁧󠁒󠁳󠁣󠁴󠁿.

You can find me on Github, on Mastodon and on Bluesky.

My Introduction to Quantum Computing with Q# and QDK book
Microsoft MVP