Rewriting a WCF service in WWS

In my last blog entry I had shown a WWS native client connecting to a WCF service. In this one I’ll talk about how the WCF service can be converted into an equivalent WWS service. Connecting clients (whether WWS, WCF, or other) would continue to behave the same. I am going to use the same c/h files that wsutil generated from the wsdl file. There is a function signature generated for us to match the service contract methods. In our case there’s just one – WSHttpBinding_IStringService_ReverseCallback. So the first thing is to add a method that matches this signature, and this will reverse a string just like the WCF service (except we write it in C or C++).

HRESULT CALLBACK Reverse(
	__in const WS_OPERATION_CONTEXT* context,
	__in WCHAR* s,
	__out  WCHAR** reverse,
	__in_opt const WS_ASYNC_CONTEXT* asyncContext,
	__in_opt WS_ERROR* error)
{
	WS_HEAP* heap = NULL;

	HRESULT hr = WsGetOperationContextProperty(
		context,
		WS_OPERATION_CONTEXT_PROPERTY_HEAP,
		&heap,
		sizeof(heap),
		error);

	if (FAILED(hr))
	{
		return hr;
	}

	hr = WsAlloc(
           heap,
           sizeof(WCHAR) * (wcslen(s) + 1),
           (void**)reverse,
           error);

	if (FAILED(hr))
	{
		return hr;
	}

	wcscpy(*reverse, s);
	wcsrev(*reverse);

	return ERROR_SUCCESS;
}

I first use WsGetOperationContextProperty to get the heap and then use WsAlloc to allocate memory for the reversed string on this heap. We do not ever allocate memory using standard memory allocation mechanisms unless it’s memory we will have the option to delete/free when we are done using it. Instead we use the WWS heap which frees us from worrying about memory leaks – the memory will be released when the heap is reset or freed.

Now let’s get to creating the service. Again, I will not show the error handling code (to save space) but every HRESULT return value must be checked for success before proceeding further. The first thing is to create the error and heap objects just as we did when writing the WWS client.

WS_ERROR* error = NULL;
HRESULT hr = WsCreateError( NULL, 0, &error);
if (FAILED(hr))
{
 // ...
}

WS_HEAP* heap = NULL;
hr = WsCreateHeap( 100000, 0, NULL, 0, &heap, error);
if (FAILED(hr))
{
 // ...
}

The next step is to create a service endpoint.

WSHttpBinding_IStringServiceFunctionTable functions = { Reverse };

WS_STRING url = WS_STRING_VALUE(L"http://localhost:8000/StringService");

WS_HTTP_BINDING_TEMPLATE templateValue = {};

WS_SERVICE_ENDPOINT* serviceEndpoint;
hr = WSHttpBinding_IStringService_CreateServiceEndpoint(&templateValue,
    &url, &functions, NULL, NULL, 0,
    heap, &serviceEndpoint, error);
if (FAILED(hr))
{
  // ...
}

Notice how we use the generated WSHttpBinding_IStringServiceFunctionTable to specify the list of functions (just one in our case). Now I use the proxy WSHttpBinding_IStringService_CreateServiceEndpoint to create the end point (and it internally calls WsCreateServiceEndpointFromTemplate). I have used default values for other arguments, but there is a lot of custom configuration that can be done. We’ll now create the service host:

WS_SERVICE_HOST* host;
const WS_SERVICE_ENDPOINT* serviceEndpoints[1];
serviceEndpoints[0]= serviceEndpoint;
hr = WsCreateServiceHost( serviceEndpoints, 1,
    NULL, 0,  &host, error);
if (FAILED(hr))
{
}

We only have one endpoint, but the service host can host multiple endpoints. While I have called WsCreateServiceHost with default arguments (basically passing NULL) it’s possible to set various service properties at this point. The last step is to open the service host.

hr = WsOpenServiceHost(host, NULL, error);

The above code will open the service and start listening on each of the endpoints (just one in our example). For a test console app, use a _getch() so the app won’t exit. Once the app’s done, close and free the service host :

WsCloseServiceHost(host, NULL, error);
WsFreeServiceHost(host);

And also free the heap/error objects :

if (heap)
{
  WsFreeHeap(heap);
}

if (error)
{
  WsFreeError(error);
}

You can now run the service and the WWS client from the last blog entry will connect to it and invoke the reverse function successfully. You can even write a simple WCF client and it’ll connect to this just as if this was a WCF service. I do agree that all these proxies, having to create/free structures, handling HRESULTs etc. may seem a tad foreign if you are coming from a pure C# or VB.NET world. But if you are not put off by C++, and keeping your service or client code native is important to you, then WWS sure seems to be a great way to do it. I do intend to research into WWS a little more in detail, so expect more blog entries and an article or two on the topic in future.

Advertisements

5 thoughts on “Rewriting a WCF service in WWS

  1. Great blog. I just have a question about the resetting heap on the server side. I saw you allocated some space in heap using WsAlloc in Reverse() call on the server side. However, in this particular example, WsResetHeap is never called on the server side, until it’s freed right before program exits. How’s the heap managed in this case? Thanks.

  2. Hi Nish
    In last week I came across this blog.
    It really helped a lot.
    I’m working in VC++ but haven’t yet worked on multithreadings and socket programmings.
    Plz guide me for these subjects.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s