Consuming a C# .NET WCF Web Service from Perl / CGI

Introduction

The chief argument for a web service is to provide a platform and language independent means of accessing a software API. This allows client programs, written in a variety of programming languages, to interact with the web service. Of course, web services also provide additional benefits, including the ability to scale in response to client traffic, provide additional security layers, and, as long as the interface contract doesn’t change, they also provide easier management of updates to the originating API code.

In this article, we’ll create a basic C# ASP .NET WCF web service for a “Hello World” example. We’ll then create a client application using Perl / CGI to consume the web service and call the web service target method. Through the usage of XML and SOAP, we’ll be able to easily communicate with the WCF web service (through any number of programming languages) and display the results.

Sign Your Life on the Dotted Line

Since we’ll be creating a simple C# ASP .NET WCF web service, we’ll first define a basic service contract. The service contract defines the interface for the WCF web service. It specifies which methods are available, the format for calling each one, and the structure of any parameters to be sent.

It’s important to note that once the WCF web service contract is published and in use by clients, it can be difficult to change without breaking existing clients. Due to this, it’s important to take careful consideration in the design of your web service interface., particularly method and data type signatures.

Drafting our own Service Contract

Luckily, our WCF web service will be simple in nature. We can define our web service contract as follows:

1
2
3
4
5
6
7
8
[ServiceContract]
public interface IService1
{
[OperationContract]
string HelloWorld(string name);
[OperationContract]
string HelloWorld2(NameData nameData);
}

In the above code, we’ve defined two methods for performing the “Hello World” functionality. The first method takes a basic string, while the second takes a complex data type. This will allow us to see the differences in calling each type from a Perl application.

We’ll also need to define the complex data type “NameData”, as follows:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
[DataContract]
public class NameData
{
[DataMember]
public string FirstName;
[DataMember]
public string LastName;
[DataMember]
public int Age;
public NameData(string firstName, string lastName, int age)
{
FirstName = firstName;
LastName = lastName;
Age = age;
}
}

Creating Our WCF Web Service

With our C# ASP .NET WCF web service contract defined, we can implement the web service, as follows:

1
2
3
4
5
6
7
8
9
10
11
public class Service1 : IService1
{
public string HelloWorld(string name)
{
return "Hello World, " + name;
}
public string HelloWorld2(NameData nameData)
{
return "Hello World, " + nameData.FirstName + " " + nameData.LastName;
}
}

In the above code, we’ve simply implemented the IService1 service contract interface and filled out the bodes for the two HelloWorld methods.

You may wish to also decorate the service in order to view the raw incoming and outgoing SOAP XML requests by using the Inspector class. At this point, you can run the web service and test the WCF service methods using Visual Studio’s built-in WCF Test Client.

SOAP on a Diet

We’re now ready to create a client app in Perl, which will call the two HelloWorld methods and output the response. Since we’ll need to form XML SOAP packets to send to the WCF web service, we’ll take advantage of the Perl library, SOAP::Lite (included in the Windows 7 installation of Perl via Strawberry Perl).

Our Perl program appears, as follows:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
#!/usr/bin/perl

package main;
use SOAP::Lite;

# Variables
my $url = 'http://localhost/WcfService1/Service1.svc?wsdl';
my $url_debug = 'http://localhost:11040/Service1.svc?wsdl';
my $uri = 'http://tempuri.org/';
my $xmlns = 'http://schemas.datacontract.org/2004/07/WcfService1';

# Setup Network Connection
my $soap = SOAP::Lite
-> uri($uri)
-> on_action(sub { sprintf '%sIService1/%s', @_ })
-> proxy($url)
->autotype(0)->readable(1);

# Call HelloWorld
my $response = $soap->HelloWorld(SOAP::Data->new(name => 'name', value => 'Johnny Five'));

# Print the Result
if ($response->fault)
{
die $response->faultstring;
}
else
{
print $response->result;
print "\n";
}

# Call HelloWorld2
$response = $soap->HelloWorld2(SOAP::Data->new(name => 'nameData', value => [
SOAP::Data->new(name => 'a:FirstName', value => 'Henry'),
SOAP::Data->new(name => 'a:LastName', value => 'Higgens'),
SOAP::Data->new(name => 'a:Age', value => '42')
])->attr( { 'xmlns:a' => $xmlns } )
);

# Print the Result
if ($response->fault)
{
die $response->faultstring;
}
else
{
print $response->result;
print "\n";
}

In the above code, we’ve created a simple Perl CGI program, which imports the SOAP::Lite library. We define our variables for accessing the WCF web service, which include a URL pointing to the web service, a namespace URI, and an XMLNS named URL (used for recognizing the complex data type “NameData”). The XMLNS named URL can be found in the web service’s WSDL file, defined for the data type in queston (search for “xsd:import schemaLocation” and the XSD definition for your desired data type).

A Primitive Data Type Web Service Call

We make the actual call to the WCF web service via “$soap->HelloWorld”, and supply the string parameter “name”. The result from the web service call is outputted to the console screen. It’s quite easy to make this call in Perl, since the parameter is a primitive string data type.

1
my $response = $soap->HelloWorld(SOAP::Data->new(name => 'name', value => 'Johnny Five'));

A Complex Data Type Web Service Call

While the first call to HelloWorld supplies basic string parameter for the name, our second HelloWorld2 supplies a complex data type “NameData”. NameData actually contains a FirstName, LastName, and Age within it. We’ll need to construct the associated SOAP XML to send to the WCF web service.

1
2
3
4
5
6
$response = $soap->HelloWorld2(SOAP::Data->new(name => 'nameData', value => [
SOAP::Data->new(name => 'a:FirstName', value => 'Henry'),
SOAP::Data->new(name => 'a:LastName', value => 'Higgens'),
SOAP::Data->new(name => 'a:Age', value => '42')
])->attr( { 'xmlns:a' => $xmlns } )
);

Notice in the above code, we’re simply constructing the complex data type as defined in the WCF web service. The one trick to the above code is the inclusion of the attribute “xmlns:a”. .NET WCF web services actually require named properties for complex data types. Therefore, we need to specify the namespace for the data type and assign an attribute name (in our case, the letter ‘a’). This allows the web service to correctly parse the XML and pass the correct parameter into the HelloWorld2 web service method. Without including the namespace, the web service would receive an empty NameData parameter, including null values for FirstName and LastName.

Running the Client Program

1
2
3
> hello.pl
Hello World, Johnny Five
Hello World, Henry Higgens

Download @ GitHub

You can download the project source code on GitHub by visiting the project home page.

Conclusion

C# ASP .NET WCF web services allow developers to implement web services that can be consumed by a variety of clients, written in any number of programming languages. By following the defined WCF web service contract and supplying the appropriate SOAP XML, client programs can interact with .NET WCF web services with ease.

About the Author

This article was written by Kory Becker, software developer and architect, skilled in a range of technologies, including web application development, machine learning, artificial intelligence, and data science.

Share