Pelco Developer Network (PDN)

Web Service Proxy Class Generation

The following are general notes and issues regarding WSDL proxy class generation by language.

C#

Please note that it is recommended that you utilize our pre-generated web service proxy classes, found in Libs\Debug\PelcoGSoapS.lib (there is a Libs\Release\PelcoGSoapS.lib version as well) as part of installing the Pelco SDK. For more details please refer to Pelco GSOAP.

You may encounter UPnP exceptions and web service timeouts in .NET with Pelco IP Cameras, by looping various requests (mostly configuration related actions and the SetRefreshInterval action). To help you avoid this situation, please either examine or just simply use our C# samples, as opposed to generating your own proxy classes.

  • In particular, our C# samples add overrides for each web service proxy class that was automatically generated by Visual Studio (from the WSDLs):
  • For the GetWebRequest Method, turn KeepAlive off.
  • For the GetWriterForMessage, just avoid sending empty XML strings.
  • Sarix cameras do not include "100 CONTINUE" in SOAP responses so tell the Windows ServicePointManager to NOT expect it by setting the Expect100Continue attribute to false:
positioningControl.Url = "http://" + cameraIP + ":" + cameraPort + "/control/PositioningControl-" + serviceId;System.Net.ServicePointManager.FindServicePoint(new Uri(positioningControl.Url)).Expect100Continue = false;

C++

This entry may be out of date, and is slated be updated in the near future.

Please utilize the PelcoGSOAP utility that is now a component of the Pelco API SDK. All of its required dependencies for the sample code are included with the Pelco API SDK installer, which can be found within the Downloads section. For details on PelcoGSOAP, please refer to the PelcoGSOAP section .

It is very difficult to incorporate new gSOAP web service proxy classes to an existing C++ app if you take the default path suggested by gSOAP. This results in so many link errors, that you virtually have to produce separate applications for each use case.

There is an alternative method. Use C++ namespaces instead of the standard xml namespace that gSOAP generates. The idea is to hide each service proxy class in separate C++ namespaces, that you do not have to worry about conflicts when you are incorporating another service. Furthermore, including all the namespaces in one nsmap file produce poorly formatted HTTP packets. All the service URNs being used is sent in every method call even though it may not be relevant to that method.

Generate the header files from the WSDL

Type and run the following command:

wsdl2h -o VideoOutput.h VideoOutputV1.wsdl

This will generate a header file. Do not include this header file in your project. This is used by the gSOAP to generate the stub and proxy classes.

Never use the -p option with the 'wsdl2h' command. Using the -p option will generate polymorphic types with C++ inheritance with base xsd_anyType. This will generate SOAP messages that include the type of object along with the regular tags:



While all the Pelco devices will accept this message format, they will not respond with a similar response message structure; which is not what gSOAP expects and this will cause problems. The errors resulting from this are subtle; there are no obvious run-time errors or thrown exceptions. Consequently they are hard to isolate and debug.
For example the gSOAP proxy class data type, streamCatalog, will have 0 entires; though if you look at the response packet, in a packet sniffer such as wireshark, you will see that there are indeed some catalogentries.
Compile the header file with soapcpp2.

Starting compiling the header file by typing and running the following command:

soapcpp2 -i -L -C -d./out -I. -pVideoOutput -qVideoOutput -x VideoOutput.h

Descriptions for understanding soapcpp2's options are below:
-i — With this option, soapcpp2 generates service proxies and objects inherited from SOAP data types. Given the above example, this will produce a C++ class of VideoOutputVideoOutputProxy. Consequently initializing the SOAP run time is as easy as instantiating an object for this proxy class. The configurable end point is also now a public member in that proxy.

-L — This option tells soapcpp2 not to generate soapClientLib/soapServerLib files. This is a recommended option.

-C — Having this option, soapcpp2 will only generate client code. This is recommended since you are not implementing a SOAP service.

-d — The -d option directs where your generated stubs and proxies will be created. './out' is the location given in the above example.

-I — This shows a list of files in the import directory. To enable this feature, copy the stlvector.h (from the gsoap installation directory) to the directory from which you are running the soapcpp2 command.

-x — Given the x option, soapcp2 will not generate any sample xml message files.

-q — This specifies C++ namespaces.

-p — The stubs generated are usually prefix by 'soap'. Since you need multiple stubs for each WSDL, it is ideal to give them a name. It is good practice to use the same name specified for the C++ namespaces. Consequently your file naming pattern should be similar to the following: VideoOutputStub.h, VideoOutputC.cpp VideoOutputH.h

Copy all the files generated to application directory.

Do not forget to copy the stdsoap2.h and stdsoap2.cpp files to your application directory; These files include the gSOAP runtime.

Generate default SOAP bindings.
If you do not follow the instructions in this section, your project may have link errors.
  • Create an empty header file env.h in your working directory.
  • Compile it with soapcpp2 -penv env.h
  • Copy envH.h, envStub.h and envC.cpp to your project directory and add it to your project.
  • Copy the following to the very top (just after #ifndef WITH_NOIDREF):
    SOAP_NMAC struct Namespace namespaces[] = {    {"SOAP-ENV", "http://schemas.xmlsoap.org/soap/envelope/", "http://www.w3.org/*/soap-envelope", NULL},    {"SOAP-ENC", "http://schemas.xmlsoap.org/soap/encoding/", "http://www.w3.org/*/soap-encoding", NULL},    {"xsi", "http://www.w3.org/2001/XMLSchema-instance", "http://www.w3.org/*/XMLSchema-instance", NULL},    {"xsd", "http://www.w3.org/2001/XMLSchema", "http://www.w3.org/*/XMLSchema", NULL},    {NULL, NULL, NULL, NULL}};
This is only used to compile your project. It will never be used.
Lean namespaces in method calls.

Typically developers include the generated nsmap file in their projects and link it (when compiled) with the rest of their project. However all method calls refer to this mapping table, in order to supply xmlns namespace mapping. Unfortunately, this will create an HTTP packet with less than ideal formatting. To avoid this situation, create a file named 'NameSpaces.h' and add the following:

You may need to add separate structures for each of the services. The following examples are the namespace structures for VideoOutput and CameraConfiguration:

SOAP_NMAC struct Namespace namespaces[] = {    {"SOAP-ENV", "http://schemas.xmlsoap.org/soap/envelope/", "http://www.w3.org/*/soap-envelope", NULL},    {"SOAP-ENC", "http://schemas.xmlsoap.org/soap/encoding/", "http://www.w3.org/*/soap-encoding", NULL},    {"xsi", "http://www.w3.org/2001/XMLSchema-instance", "http://www.w3.org/*/XMLSchema-instance", NULL},    {"xsd", "http://www.w3.org/2001/XMLSchema", "http://www.w3.org/*/XMLSchema", NULL},    {NULL, NULL, NULL, NULL}};

Add a separate structure for each of the services. Moreover, do not forget to include this NameSpace.h in the project. Here is sample code on how to initialize a SOAP runtime, add an endpoint, and use a separate namespace for each of the services.

SOAP_NMAC struct Namespace namespaces[] = {    {"SOAP-ENV", "http://schemas.xmlsoap.org/soap/envelope/", "http://www.w3.org/*/soap-envelope", NULL},    {"SOAP-ENC", "http://schemas.xmlsoap.org/soap/encoding/", "http://www.w3.org/*/soap-encoding", NULL},    {"xsi", "http://www.w3.org/2001/XMLSchema-instance", "http://www.w3.org/*/XMLSchema-instance", NULL},    {"xsd", "http://www.w3.org/2001/XMLSchema", "http://www.w3.org/*/XMLSchema", NULL},    {NULL, NULL, NULL, NULL}};