Click here to Skip to main content
15,881,882 members
Articles / Web Development / IIS
Article

Your first managed C++ Web Service

Rate me:
Please Sign up or sign in to vote.
4.80/5 (11 votes)
17 Oct 2001CPOL4 min read 304.6K   3.1K   57   34
An introduction to writing your first WebService using C++ with managed extensions

Introduction

This article assumes you are familiar with declaring and using managed types and the .NET Garbage Collector.

Creating your first web service is incredibly easy if you use C# or VB.NET (see my previous article for details). Writing a WebService using managed C++ in .NET is also extremely simple, but there are a couple of 'gotcha's that can cause a few frustrating moments.

My first suggestion is to use the Visual Studio .NET Wizards to create your WebService (in fact it's a great idea for all your apps when you are first starting out). This is especially important if you are moving up through the various builds of the beta bits of .NET. What is perfectly acceptable in one build may fail to compile in another build, and it may be difficult to work out which piece of the puzzle you are missing.

Using the Wizards can get you a managed C++ WebService up and running in minutes, but things can start to get a little weird as soon as you try something a little more risqué.

For this example I have created a service called MyCPPService by using the Wizard. Simply select File | New Project and run through the wizard to create a C++ WebService.

A new namespace will be defined called CPPWebService, and within this namespace will be the classes and structures that implement your webservice. For this example I have called the class MyService. Other files that are created by the wizard include the .asmx file that acts as a proxy for your service; the config.web file for configuration settings, and the .disco file for service discovery. Once you compile the class your assembly will be stored as CPPWebService.dll in the /bin directory.

I wanted to mimic the C# WebService created in my previous article, but with a few minor changes to illustrate using value and reference types. With this in mind I defined a Value Type structure ClientData and a managed reference type ClientInfo within the namespace that would both contain a name and an ID (string and int values respectively). 

__value public struct ClientData
{
	String *Name;
	int	ID;
};
__gc public class ClientInfo
{
	String *Name;
	int	ID;
};

In order to return an array of objects a quick typedef is also declared

typedef ClientData ClientArray[];

In a similar fashion I defined my MyService class as a simple managed C++ class with three methods:

  • MyMethod is a simple method that returns a single integer
  • GetClientData returns a single  ClientData structure
  • GetClientsData returns an array of ClientInfo objects
// CPPWebService.h

#pragma once
#using "System.EnterpriseServices.dll"

namespace CPPWebService
{
	__value public struct ClientData
	{
		String *Name;
		int	ID;
	};

	__gc public class ClientInfo
	{
		String *Name;
		int	ID;
	};

	typedef ClientData ClientArray[];

	__gc class MyService 
	{
	public:
		[WebMethod] 
		int MyMethod();

		[WebMethod]
		ClientData GetClientData();

		[WebMethod]
		ClientArray GetClientsData(int Number);
	};
}

The important thing to notice about the function prototypes is the [WebMethod] attribute - this informs the compiler that the method will be a method of a web service, and that it should provide the appropriate support and plumbing. The method you attach this attribute to must also be publicly accessible.

The implementation (.cpp) file is as follows.

#include "stdafx.h"
#using <mscorlib.dll>
#using "System.Web.dll"
#using "System.Web.Services.dll"

using namespace System;
using namespace System::Web;
using namespace System::Web::Services;

#include "CPPWebService.h"

namespace CPPWebService
{
	int MyService::MyMethod()
	{
		return 42;
	}

	ClientData MyService::GetClientData()
	{
		ClientData data;
		data.Name = new String("Client Name");
		data.ID = 1;

		return data;
	}

	ClientArray MyService::GetClientsData(int Number)
	{
		// simple sanity checks
		if (Number < 0 || Number > 10)
			return 0;

		ClientArray data = new ClientData __gc[Number];

		if (Number > 0 && Number <= 10)
		{
			for (int i = 0; i < Number; i++)
			{
				data[i].Name = new String("Client ");
				data[i].Name->Concat(i.ToString());
				data[i].ID = i;
			}
		}

		return data;
	}
};

Note the use of the syntax i.ToString(). In .NET, value types such as int's and enums can have methods associated with them. i.ToString() simply calls the Int32::ToString() for the variable i.

One huge improvement of .NET beta 2 over beta 1 is that you no longer need to mess around with the XmlIncludeAttribute class to inform the serializer about your structure. A few bugs that either caused things to misbehave, or worse - not run altogether - have also been fixed. Writing a WebService in MC++ is now just as easy in C++ as it is in C#, with the advantage that you can mix and match native and managed code while retaining the raw power of C++.

Once you have the changes in place you can build the project then test the service by right clicking on the CPPWebService.asmx in the Solution Explorer in Visual Studio and choosing "View in Browser". The test page is shown below.

Image 1

Clicking on one of the methods (say, GetClientsData) results in a proxy page being presented which allows you to invoke the method directly from your browser. The GetClientsData method takes a single int parameter which you can enter in the edit box.

Image 2

When invoked this returns the following:

Image 3

Conclusion

Writing WebServices using Visual C++ with managed extensions is just as easy as writing them using C# or VB.NET, as long as you remember a few simple things: use attributes, declare your classes as managed and make them publicly accessible. Using the Visual Studio.NET wizards makes writing and deploying these services a point and click affair, but even if you wish to do it by hand then the steps involved are extremely simple.

History

Oct 18 - updated for .NET beta 2

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Founder CodeProject
Canada Canada
Chris Maunder is the co-founder of CodeProject and ContentLab.com, and has been a prominent figure in the software development community for nearly 30 years. Hailing from Australia, Chris has a background in Mathematics, Astrophysics, Environmental Engineering and Defence Research. His programming endeavours span everything from FORTRAN on Super Computers, C++/MFC on Windows, through to to high-load .NET web applications and Python AI applications on everything from macOS to a Raspberry Pi. Chris is a full-stack developer who is as comfortable with SQL as he is with CSS.

In the late 1990s, he and his business partner David Cunningham recognized the need for a platform that would facilitate knowledge-sharing among developers, leading to the establishment of CodeProject.com in 1999. Chris's expertise in programming and his passion for fostering a collaborative environment have played a pivotal role in the success of CodeProject.com. Over the years, the website has grown into a vibrant community where programmers worldwide can connect, exchange ideas, and find solutions to coding challenges. Chris is a prolific contributor to the developer community through his articles and tutorials, and his latest passion project, CodeProject.AI.

In addition to his work with CodeProject.com, Chris co-founded ContentLab and DeveloperMedia, two projects focussed on helping companies make their Software Projects a success. Chris's roles included Product Development, Content Creation, Client Satisfaction and Systems Automation.

Comments and Discussions

 
Generalperformance vs c# Pin
25-Sep-02 8:03
suss25-Sep-02 8:03 
Generalnamespace question Pin
6-Jul-02 8:13
suss6-Jul-02 8:13 
GeneralAgain, good one :-) Pin
Nish Nishant26-May-02 21:29
sitebuilderNish Nishant26-May-02 21:29 
QuestionRe: Again, good one :-) Pin
RedDk17-Sep-08 7:36
RedDk17-Sep-08 7:36 
GeneralWhy no number in results? Please see the detailed ... Pin
6-Mar-02 0:14
suss6-Mar-02 0:14 
Questionhow to use webservice class in webclient? Pin
18-Dec-01 0:17
suss18-Dec-01 0:17 
AnswerRe: how to use webservice class in webclient? Pin
Laurent Kempé20-Dec-01 3:31
Laurent Kempé20-Dec-01 3:31 
GeneralRe: how to use webservice class in webclient? Pin
Ranjan Banerji29-Apr-02 6:30
Ranjan Banerji29-Apr-02 6:30 
I created a web service of my own using VC++ .Net. The created a Web Application using ASP .Net. I added a web reference. But when I try to test the application I get the error listed below. Not sure what I did wrong. Any ideas?

Thanks

***********************************************************************

Server Error in '/WebApplication1' Application.

The request failed with HTTP status 401: Access Denied.

Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.

Exception Details: System.Net.WebException: The request failed with HTTP status 401: Access Denied.

Source Error:


Line 40: <system.web.services.protocols.soapdocumentmethodattribute("http: tempuri.org="" helloworld",="" requestnamespace:="http://tempuri.org/" ,="" responsenamespace:="http://tempuri.org/" use:="System.Web.Services.Description.SoapBindingUse.Literal," parameterstyle:="System.Web.Services.Protocols.SoapParameterStyle.Wrapped)"> _
Line 41: Public Function HelloWorld() As String
Line 42: Dim results() As Object = Me.Invoke("HelloWorld", New Object(-1) {})
Line 43: Return CType(results(0),String)
Line 44: End Function


Source File: e:\inetpub\wwwroot\WebApplication1\Web References\localhost\Reference.vb Line: 42

Stack Trace:

[WebException: The request failed with HTTP status 401: Access Denied.]
System.Web.Services.Protocols.SoapHttpClientProtocol.ReadResponse(SoapClientMessage message, WebResponse response, Stream responseStream)
System.Web.Services.Protocols.SoapHttpClientProtocol.Invoke(String methodName, Object[] parameters)
WebApplication1.localhost.Class1.HelloWorld() in e:\inetpub\wwwroot\WebApplication1\Web References\localhost\Reference.vb:42
WebApplication1.WebForm1.Page_Load(Object sender, EventArgs e) in e:\inetpub\wwwroot\WebApplication1\WebForm1.aspx.vb:34
System.Web.UI.Control.OnLoad(EventArgs e)
System.Web.UI.Control.LoadRecursive()
System.Web.UI.Page.ProcessRequestMain()

**************************************************************************
GeneralRe: how to use webservice class in webclient? Pin
Laurent Kempé29-Apr-02 13:21
Laurent Kempé29-Apr-02 13:21 
GeneralAccesing Web References at Rutime Pin
6-Nov-01 1:39
suss6-Nov-01 1:39 
GeneralAccessing the Web service through C++ code Pin
5-Jun-01 23:20
suss5-Jun-01 23:20 
GeneralRe: Accessing the Web service through C++ code Pin
Anonymous18-Sep-02 15:29
Anonymous18-Sep-02 15:29 
GeneralAccessing Web Services from Web Client Pin
STEVBI17-May-01 13:43
STEVBI17-May-01 13:43 
GeneralDeployment problem Pin
Kannan Kalyanaraman3-Apr-01 20:40
Kannan Kalyanaraman3-Apr-01 20:40 
GeneralRe: Deployment problem Pin
Chris Maunder3-Apr-01 21:30
cofounderChris Maunder3-Apr-01 21:30 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.