No account yet?
 
Home arrow Resources arrow Creating a GW SOAP Session in C#/.NET 2.0

Syndicate

Creating a GW SOAP Session in C#/.NET 2.0

This article focuses on how to consume GroupWise Web Services in a .NET C# application written for .NET 2.0, and how to log in as a specific user either using specific login credentials, or as a trusted application. 

Executive Summary

This section provides a brief outline of prerequisites and assumptions, along with a complete code sample, for quick reference. 

This code sample was designed for and tested with C# under .NET 2.0 on Visual Studio 2008.  Syntax and even procedures ARE DIFFERENT with different versions of .NET, Visual Studio, and with different languages (duh).

Pre-requisites and Assumptions:

  • Add a web reference to your project for the GroupWise WSDL.  The namespace for the Web Reference is "gwws".
  • Ensure your POA is configured with SOAP enabled, and that you know the SOAP port
  • Ensure there are no local or remote firewalls that might get in the way.
  • This code works with a form that has a ListBox control named "listBox1".

Code:

This sample logs in, gets a list of Proxy accounts that the user has proxied to before, and logs out.

           
// create the GroupWiseBinding object and set the URL
gwws.GroupWiseBinding gw = new gwws.GroupWiseBinding();
gw.Url = "http://poa.company.com:7191/soap";

// create the Authenticate object
gwws.PlainText ptAuth = new gwws.PlainText();
ptAuth.username = "testuser1";
ptAuth.password = "password";

// create the login request
gwws.loginRequest lreq = new gwws.loginRequest();
lreq.auth = ptAuth;

// send the login request
try
{
gwws.loginResponse lresp = gw.loginRequest(lreq);
// check for an error and throw an exception if there is one
if (lresp.status.code != 0)
{
gwws.Status status = lresp.status;
String msg = String.Format("Error logging in: {0} - {1}",
lresp.status.code, lresp.status.description);
throw new Exception(msg);
}
}
catch (Exception ex)
{
// log the error, etc.
// note that we may end up here for reasons other than the
// POA failing our login. you may wish to define a special Exception
// class for login failures, etc.
return;
}

// create the session object to store the session ID for future calls to
// Web Services for this login
gw.session = new gwws.@string();
gw.session.Text = new string[1];
gw.session.Text[0] = lresp.session;

// create the getProxyListRequest object
gwws.getProxyListRequest plreq = new gwws.getProxyListRequest();

// send the proxy list request
try
{
gwws.getProxyListResponse plresp = gw.getProxyListRequest(plreq);
// check for an error
if (plresp.status.code != 0)
{
gwws.Status status = plresp.status;
String msg = String.Format("Error getting proxy list: {0} - {1}", plresp.status.code, plresp.status.description);
throw new Exception(msg);
}
}
catch (Exception ex)
{
// handle the exception, etc.
// note that we may end up here for reasons other than
// getting a non-zero status code from the POA.
// note also that you really should log out here, and destroy the
// GroupWiseBinding object. we are being lazy here. ;)
return;
}

// note: GW is notirious for sending nothing at all in place of an empty list.
// I.E. it might be possible to have "plresp.proxies == null" if the user has
// no proxy items in their list, rather than getting back a plresp.proxies
// object that is just empty. Be sure to code defensively!
foreach (gwws.NameAndEmail proxy in plresp.proxies)
{
try
{
listBox1.Items.Add(proxy.displayName);
}
catch (Exception ex)
{
// GW is notirious for sometimes sending "nothing"
// rather than empty lists
}
}

// create the logout request
gwws.logoutRequest logoutreq = new gwws.logoutRequest();

try
{
gw.logoutRequest(logoutreq);
}
catch (Exception ex)
{
// handle the logout exception here
// note that we may end up here for reasons other
// than a status.code != 0
return;
}

 

Development Environment 

NOTE: This article deals with Visual Studio 2008, C#, and .NET 2.0.  Visual Studio 2008 also supports .NET 3.0 and .NET 3.5 (as well as other languages, like VB.NET).  The overall strategy will work with the other .NET releases, and with other languages, but the menu item names, and in some cases, procedures, will vary.  This article should still be useful to you, but you will have to do some manual research as well.  Keep an eye out for other articles with specifics on the environment and language you are interested in (if VS2008/.NET 2.0/C# isn't exactly what you are working with.)

When you want to make use of GroupWise Web Services (a.k.a. SOAP services), the steps, process, and syntax vary a little from one development environment and language to another.  The nice thing about SOAP-based services is that they are designed by the vendor/producer without regard to the development environment or language to be used.  That way, anyone can consume those services and write applications that handle the system, regardless of their language, platform, or environment.

However, because the interface to the services is NOT specific to an IDE or language, it is necessary to somehow convert the API definitions into structures and constructs that make sense to the language and IDE you are using.  SOAP service designers/producers rightly assume that each IDE developer will create some way to interpret the standard SOAP definitions, and create classes and interfaces that make sense to the language and IDE.

Unfortunately, this gives rise to differences (sometimes VAST differences) in the syntax and other properties of the implementation.

In this article, I will show how to consume GroupWise Web Services in your application, and how to log into a GroupWise account, both with specific login credentials, and as a trusted application.  I will focus on the .NET platform and C#.  The ideas and general steps to perform are very similar on other platforms, but there are differences, so YMMV.  (There will be future articles for this topic as it relates to other environments, like Java, PHP, and Perl.)

Setting Up GroupWise

Before you can have an application successfully connect to a GroupWise POA via the SOAP protocol, you must configure the GroupWise system.

To do this, you must follow four steps:

  1. Enable SOAP on the POA
  2. Specify/verify the SOAP TCP port number for the POA
  3. Restart the POA
  4. Ensure that your application can connect to the POA on the configured port without being impeded by any TCP/IP stack issues, including local and remote firewalls

The enabling of SOAP and configuring of the POA port are both done on the POA object properties in ConsoleOne.  They can also be done through command line options specified on the command line, or in the POA startup file.  Refer to the GroupWise documentation for information on how to do that.

Configuring the POA in ConsoleOne
POA Startup Switches

Creating a Reference to GW Web Services

The first step to being able to use GroupWise Web Services is to create the classes, interfaces, and other definitions  that represent the GroupWise system, and that allow you to make calls to the GroupWise system to request data, perform actions, etc.

SOAP data objects and services are defined in a standard way, using XML, and a syntax known as "Web Services Description Language" (or WSDL - pronounced "wiz-dull").  Because a WSDL is written in an "agnostic" syntax (without regard to a particular programming language or environment), it must be converted into class and interface definitions for use in C#.

SOAP was first implemented (and supported) with GroupWise v7.0.  There have since (as of this writing - January 2009) been three service packs (SP1, SP2, and SP3).  In addition, GroupWise v8.0 has been released, and has yet another version of the WSDL.  The initial releases of v7.0 and v8.0, and each v7.0 service pack, all have variations to the WSDL schema, bug fixes, etc.  Thus, you have to target a specific release of GroupWise with your project.  Because of this, you must download the WSDL for the version you intend to develop for. They can be found at the Novell Developer's home page (drill down to GroupWise, and further down to GroupWise Web Services.)   (Note: I suppose it would be possible to create multiple references in your project, each to a GW WSDL for a specific version of GroupWise, and thus support all versions of GroupWise.  I have never done that, and how to do so is beyond the scope of this article.)

To convert the GrouopWise WSDL into C#-friendly classes etc., you need to add a "Web Reference" to your project.  Simply right-click on the "References" item in the Solution Explorer, and select "Add Web Reference".  This will display a dialog box that requests the "URL" of the web service.  The labels and descriptions of this process in Visual Studio 2008 presume that the SOAP service that you want to add a reference to is defined online, and that the provider of that service has published the WSDL you want using a web server.

This is NOT the case with GroupWise.  It's not clear from the "Add Web Reference" dialog box, but you can type in a local file path in the "URL:" box.  This is what you will need to do for GroupWise: type in the path to the WSDL of your choice.

After typing in the path, click the "Go" button, and VS2008 will process the WSDL and identify the different data types defined in it, various classes that should exist, etc.  It should indicate "1 Service Found" in the "Web services found at this URL:" text box, along with the name of the service, "groupwise".

You are also prompted for the "Web reference name" for the web service.  You can type in whatever you like - this is the name of the namespace that the GroupWise class defintions will belong to in your project.  You will be referring to this namespace in your code as you instantiate GroupWise Web Services objects, call methods, etc., so I recommend that you call it something that is related to GroupWise, and that makes it clear what it is.  (I also have a penchant for keeping code readable, so my personal choice is something short.)  I almost always use "gwws" (all lower case, just FYI, though that is NOT a requirement - it's just my style.).

After processing and naming the service, click the "Add Reference" button.  You now have a new namespace in your project (presumably called "gwws", if that's the name you gave it).

Instantiating GroupWise Web Services

In order to log into GroupWise, you need to have an "instance" of the GroupWise Web Services system.  This is your starting point.

There are many classes and interfaces defined in the WSDL.  Which one should you use as the "starting point"?  The answer is:  GroupWiseBinding.  However, note that this is the answer for C# under .NET 2.0, in Visual Studio 2008.  If you use .NET 3.5, it is something different.  (also if you use Java).  As mentioned before, these instructions are specific to the environment described!

Sample code for creating a GroupWiseBinding object appears in the next section. 

Once you have an instance of the GroupWiseBinding class, you must tell the GroupWise Web Services system how to connect to your GroupWise POA.  This is done through the Url field on the GroupWiseBinding class:

gwws.GroupWiseBinding gw = new gwws.GroupWiseBinding();
gw.Url = "http://poa.mycompany.com:7191/soap";

 

Note that the Url must tinclude the "http://" prefix, and must include the SOAP port that is configured for your POA.   In addition, it must include the "/soap" postfix.  This tells the POA that you intend to send and receive SOAP requests/responses.  Otherwise, your application will be redirected to the POA's HTTP management console.

With this, you are ready for the next step.

Logging In With a User Password

After you have a GroupWiseBinding object, you can log in.  It is assumed that you know the user ID of the mailbox you want to log into.  (The oft-requested feature for an API that reads the user's mind is being looked at, but won't be included until some future version of GroupWise.)

Once you know the user ID of the mailbox you want to log into, there are two ways to authenticate to that mailbox:

  1. Use the user's password
  2. Use  Trusted Application credentials

This section will demonstrate logging in with a user password.

To log in, you must follow these steps:

  1. Create and populate an Authention object
  2. Create and populate a loginRequest object
  3. Pass the loginRequest object to the loginRequest method
  4. Retrieve and examine a loginResponse object

These steps are outlined blow.  Sample code appears at the end of this section.

Create an Authentication Object

Remember that the name I used for the GroupWise Web Services namespace when I added a Web Reference for the GroupWise WSDL is "gwws".

The gwws.loginRequest object contains a member of type gwws.Authentication.  Authentication objects contain authentication (login) criteria.  The Authentication class is an abstract base class.  There are three subclasses that you can use with a loginRequest object:

  • PlainText
  • TrustedApplication
  • Proxy

The PlainText class is the class you would use for logging in with a user's password. 

There are two fields for the PlainText object:

  • username
  • password
Specify each of these fields. 

Create a loginRequest Object 

After you have created the PlainText object and populated it with the user's password, you must create a loginRequest object.

There are a number of fields on a loginRequest object, but the only one that is required is the "auth" field. It is an object pointer that can point to any type of Authentication object.  You want to point it at your PlainText object.

You can also modify the loginRequest.application string with any arbitrary value you wish.  This string can help to troubleshoot issues, as it is used in login log entries on the POA.

The response to a loginRequest call is a loginResponse object, which includes an instance of "UserInfo".  The UserInfo object can be made to contain information about the user's Post Office and Domain, if you want.  To indicate that you want this data returned, set the loginRequest.userid boolean field to "true".

Call the loginRequest Method 

Now that you have a loginRequest object, and your GroupWiseBinding object is configured with the correct URL for your POA, you can call the loginRequest method.  This method exists on the GroupWiseBinding class.  It is not a static method, so you must call this method from a GroupWiseBinding instance.  You pass your loginRequest object to the loginRequest method.  I know, it's a little confusing. 

The loginRequest method returns a loginResponse object (if there isn't some other exception).  So you need to have a variable of type loginResponse to receive the loginResponse object that is returned.  It works like this:

gwws.loginResponse loginresp = gw.loginRequest(loginreq);

That's it!  Once you are done with this, you can examine and work with the loginResponse object.

Examine the loginResponse Object 

The loginRequest method returns a loginResponse object.  As shown above, you want to have a variable to receive this object, so you can work with it.

The GroupWise Web Services structure makes heavy use of this "request-response" mechanism (that's how SOAP works).  With GroupWise, every "response" type object (i.e. loginResponse) includes a "status" member.  This includes a status "code", a "description" string, and other items.  If loginResponse.status.code == 0, then everything went fine.  Otherwise, there was a problem.  You should check this code and handle it some way.  Our sample code does NOT do this, so as to  

One of the fields on the loginResponse object is a string which identifies the logged-in GroupWise "session" (a.k.a. the "session ID").  This session ID must be available to  your GroupWiseBinding object in order for you to perform any function on the mailbox you are logged into.  When you call methods on the GroupWiseBinding object, it passes this session ID along with the request to the GroupWise POA, so the POA knows which mailbox the request is for, etc.

The GroupWiseBinding object contains a field named "session".  You would think that this would be defined as a simple string field, but it's not.  It's actually an instance of a GroupWise Web Services class named "@string".  I think that placing an "@" at the beginning of a class name is VS2008's way of resolving class names when they conflict with classes in other assemblies, or with simple types built into the language.  Clearly, "string" is a class name that would conflict.  I suspect there was a badly named (or poorly parsed) definition in the WSDL.

What's more, the type isn't just defined as a simple type, but rather as a class.  The lone field on the class is "Text", which is an array of strings.  I am not sure why this is useful - there is only one session ID per session, so I am not sure why you would want to store multiple strings in the GroupWiseBinding.session object.

In any case, you have to store the session ID that comes back in the loginResponse object.  You do this by creating an @string object, then creating a strings array (with one element) and assigning it to the @string.Text field.  You then store the session ID in the element in the array.  This is done this way:

gwws.PlainText ptAuth = new gwws.PlainText();
ptAuth.username = "testuser1";
ptAuth.password = "password";
gwws.loginRequest loginreq = new gwws.loginRequest();
loginreq.auth = ptAuth;
gwws.loginResponse loginresp = gw.loginRequest(loginreq);

gw.session = new gwws.@string;
gw.session.Text = new string[1];
gw.session.Text[0] = loginresp.session;

test