4
votes

I want to create an Exchange Web Services (EWS) client application using Delphi XE6.

I am using a THttpRio component with a wsdl. How do I set the user credentials? In other languages, the equivalent of the THttpRio component has a Credentials property (example). But this is missing from the Delphi component.

The authentication mechanism (apart from impersonation) is not part of the ews wsdl. It is native to the SOAP layer.

Listing 1:

procedure TForm1.Button1Click( Sender: TObject);
var
   lESB        : ExchangeServicePortType;
   request       : GetServiceConfiguration;
   Impersonation : ExchangeImpersonation;
   RequestVersion: RequestServerVersion;
   MailboxCulture1: MailboxCulture;
   GetServiceConfigurationResult: GetServiceConfigurationResponse;
   ServerVersion : ServerVersionInfo;
begin
lESB := HTTPRIO1 as ExchangeServicePortType;
request         := GetServiceConfiguration.Create;
request.RequestedConfiguration := ArrayOfServiceConfigurationType.Create( 'UnifiedMessagingConfiguration');
Impersonation   := ExchangeImpersonation.Create;
RequestVersion  := RequestServerVersion.Create;
MailboxCulture1 := MailboxCulture.Create;
GetServiceConfigurationResult:= GetServiceConfigurationResponse.Create;
ServerVersion                := ServerVersionInfo.Create;
try
lESB.GetServiceConfiguration(
  request, Impersonation, RequestVersion, MailboxCulture1,
  GetServiceConfigurationResult, ServerVersion)
finally
  request.Free;
  Impersonation.Free;
  RequestVersion.Free;
  MailboxCulture1.Free;
  GetServiceConfigurationResult.Free;
  ServerVersion.Free
  end
end;

Listing 1 above, shows some sample code, that I have tried so far. The purpose of the function is to get the version information about the server. HTTPRIO1 is a THTTPRIO component with default properties, and hooked up to the standard wsdl for EWS. This doesn't work because user credentials are not set.

How to set the user credentials?

1
I never got this to work in Delphi, I ended up making an intermediary .NET DLL where you can consume it quite easily. - whosrdaddy
Instead of using HttpRIO I would strongly encourage you to use Indy components in order to consume an EWS wsdl. - RBA
@RBA could you add some details (maybe as a full answer)? There is no Indy based drop-in replacement component for THttpRIO. Indy (TIdHTTP) may be used to download a web-based WSDL resource, but that would not help solving the actual interop problem. - mjn
What about THTTPRIO.HTTPWebNode (THTTPReqResp) property where you have the UserName/Password, or did I miss something? - kobik
Offtopic, but how did you manage to import WSDL? - iPath ツ

1 Answers

0
votes

After a lot of trial and error, this is the solution that I came up with...

(1) Authentication

If using the THTTPRio component, the UserName/Password pair of properties of the HTTPWebNode property of the THHPRio can be used to identifiy the credentials of the user, from the perspective of establishing an internet connection through a proxy server.

If using the THTTPReqResp component, the same UserName/Password properties are directly owned by the component.

If using the TIdHTTP, there are proxy related properties to use.

If you want to use the credentials of the currently logged on, with explicitly passing the password onto the component, you can achieve this by leaving blank, the UserName and Password properties of the THTTPRio and THTTPReqResp components. Proxy information will be automatically picked up from the system registry. However TIdHTTP is different. This component required proxy configuration to be set up explicitly, including the credentials of the internet user.

(2) What component to use for EWS Soap transactions?

I could not get the standard soap solution, the THTTPRio component, to work. The problem was that the THTTPRio component did not produce the correct shape of request envelope. Without going into detail, there were numerous issues such as elements that should have been placed in the body, would appear in the header instead, and schema violations. If you can get this (THTTPRio based on the published wsdl) to work, (but I doubt it), it is worth noting that the wsdl needs to be tweeked to include the service node. Microsoft deliberately excluded the service node for security reasons, but it is needed for correct operation of the Delphi soap wizard.

Developing a solution based on TIdHTTP is a non-starter, if your application sits behind a firewall and must negotiate with a proxy server.

The simplest and best solution is to use the THTTPReqResp component. You don't even need the wisdl for this. You must craft your own xml request envelopes, but with Microsoft's excellent documentation, showing simple envelopes, this task is a doddle.

(3) On using THTTPReqResp to access EWS

  1. EWS uses UTF-8, so set UseUTF8InHeader := True
  2. Set InvokeOptions = [soIgnoreInvalidCerts, soAutoCheckAccessPointViaUDDI]
  3. Set the URL to the service server URL, as required.
  4. Set SoapAction to http://schemas.microsoft.com/exchange/services/2006/messages
  5. Set UserName and Password as required, or leave empty to use the credentials of the logged-on user.
  6. EWS uses soap 1.1, not 1.2, so exclude wnoSOAP12 from WebNodeOptions.
  7. Leverage MSDN online. It's a superb resource with plenty of examples.

(4) On building XML documents.

Soap envelopes are XML documents following a specific published format, with your request data embedded. How to build these envelopes?

Here two possible ways that worked well for me:

  1. Use a template software design pattern. For example I use a component very similar to the TPageProducer. The source your basic template, and you use tag replacement to achieve your desired result. My version of the PageProducer can define optional fragments, or fragments that are repeated n times (with different data per iteration), marked up within the one template.
  2. Use XSLT. This is the simplest solution. It is almost code free.

Here are two possible ways, that you might use, but I recommend against. It is not that they do not work, but just that the techniques are too clumsy and take too much coding:

  1. Manually construct the document as a string (or use string builder) part-by-part.
  2. Build the document, part-by-part using the standard XML interfaces (IXMLNode etc), and then stream out the result.