Several weeks ago, in my first “Developer Diary” about using OpenAmplify, I mistakenly thought that OpenAmplify did not have a SOAP interface. Since then, I’ve learned that there actually is a SOAP interface to OpenAmplify. Today, I am going to show you what it takes to work with that interface from Visual Studio. Please note that I am using VS 2008, and if you are using an older version of Visual Studio, some of the instructions may be slightly different when it comes to establishing the initial connection to the service.

The first step in using OpenAmplify via SOAP is to create a Web Reference to it in your project. To do this, right click “Service References” in your project, and choose “Add Service Reference”.

Enter the http://portaltnx.openamplify.com/AmplifyWeb_v11/wsdl/WSAmplify_v1_1.wsdl into the URL box in the dialog and “com.openamplify.portaltnx” in the namespace field then click the “OK” button. This automatically creates a namespace of “com.openamplify.portaltnx” under your project’s default namespace which contains all of the needed classes to make a request to OpenAmplify.

Before you make a request, though, you will need to open the file app.config to make a few changes. In the file you will see an element called “endpoint” which has an address attribute. Make sure that the endpoint attribute has this value in it:

http://api.openamplify.com/axis2/services/WSAmplify_v1_1Service

You will also need to take a look at the binding element, and set the “maxBufferSize” and “maxReceivedMessageSize” attributes to 6553600. This will ensure that the SOAP client is willing to accept all of OpenAmplify’s output, which can be rather large. Finally, you will need to change the following timeout values in the binding, since the SOAP service can occasionally take longer than the default timeouts on very long documents:

  • closeTimeout: 0:10:00
  • openTimeout: 0:10:00
  • receiveTimeout: 0:20:00
  • sendTimeout: 0:10:00

Before you send your text to the SOAP service, you will need to scrub it first. For one thing, OpenAmplify’s SOAP service does not accept Unicode input, so you will need to convert Unicode to ASCII. Here is the function I wrote which does the trick:

private string UnicodeToAscii (string input)

{

var asciiEncoder = Encoding.GetEncoding(“us-ascii”, new EncoderReplacementFallback(string.Empty), new DecoderReplacementFallback(string.Empty));

var encodedBytes = new byte[asciiEncoder.GetByteCount(input)];

asciiEncoder.GetBytes(input, 0, input.Length, encodedBytes, 0);

return asciiEncoder.GetString(encodedBytes);

}

You will also need to strip out any less-than and greater-than symbols before passing the text along. At the time of this writing, the service will interpret them as unescaped XML and not work properly.

You are now ready to create a basic request to OpenAmplify. The code to do this is very simple:

private AmplifyScorecard GetOpenAmplifyResults2(string openAmplifyInput, string apiKey)

{

openAmplifyInput = UnicodeToAscii(openAmplifyInput);

openAmplifyInput = openAmplifyInput.Replace(“<“, string.Empty);

openAmplifyInput = openAmplifyInput.Replace(“>”, string.Empty);

var amplifyService = new WSAmplify_v1_1Client();

var amplifyParameters = new List<Param>();

var apiKeyParameter = new Param {Name = “apiKey”, Value = apiKey};    amplifyParameters.Add(apiKeyParameter);

AmplifyScorecard results = null;

results = amplifyService.Amplify(openAmplifyInput, amplifyParameters.ToArray());

return results;

}

Of course, you will need to have a using (or Imports for VB.NET users) statement in your class that refers to the service’s namespace that we created earlier.

There are two things to note here. The first is that I am declaring my parameters as a List<Param> object even though the WSAmplify_v1_1Service.Amplify() method expects an array of Param objects. This reason for this is that List<T> is much friendlier to work with, particularly when the number of parameters is unknown in advance.

The other important item here is that each parameter consists of a name/value pair (accessed via properties of the same name). The Name property of the parameter should match the name that you would use when making a POST to OpenAmplify. This means that, at a minimum, I need to provide the key “apiKey”. The full list can be found here in the documentation.

If you want to perform an OpenAmplify “Search” instead of a full analysis, you replace the call to the Amplify() method with a call to the Search() method. Search() will provide an AmplifyScorecard object as the return results just like Amplify() does.

Once we have the results, what can we do with them? Let’s take a look at the AmplifyScorecard object. It has a number of properties which correspond to the equivalent results in the XML output:

  • Actions
  • Demographics
  • Styles
  • TopicIntentions
  • Topics

It also adds the property Search, which I will address shortly.

Central to this discussion is the Result class. Result is a simple class, with only two properties, Name and Value. Both of these properties are of type string. The Name and Value properties of Result objects corresponds to the elements of the same name in the XML output.

Let’s take a closer look at these properties, since they are where the action is. Luckily for us, all of the items at the very bottom of the object trees (anything of type Result) correspond perfectly to the XML elements by the same name in the OpenAmplify documentation.

Actions

Actions is of type ActionScorecard. Within that type there is only one member, TopActions, which is an array of ActionResult objects. ActionResult objects contain the following fields:

  • Action: Result
  • ActionType: Result[]
  • Decisiveness: Result
  • OfferingGuidance: Result
  • RequestingGuidance: Result
  • TemporalityResult: Result[]

Demographics

The Demographics property has the type DemographicsScorecard which consists of these properties:

  • Age: Result
  • Education: Result
  • Gender: Result
  • Language: Result

Styles

Styles like Demographics is very simple. It is a StyleScorecard object with these two fields:

  • Flamboyance: Result
  • Slang: Result

TopicIntentions

TopicIntentions is of type TopicIntentionScorecard. This class is fairly complex with the following fields:

  • Domains: DomainResult[ ]
    • Domain: Result
    • Subdomains: SubdomainResult[ ]
      • Scores: Result[ ]
      • Subdomain: Result
  • Locations: Result[ ]
  • ProperNouns: TopicIntentionResult[ ]
    • OfferingGuidance: Result
    • Polarity: PolarityResult
      • Max: Result
      • Mean: Result
      • Min: Result
    • RequestingGuidance: Result
    • Topic: Result
    • TopicIntention: TopicActionTypeResult[ ]
      • ActionType: Result
      • TopicRoles: TopicRoleResult[ ]
        • Decisiveness: Result
        • OfferingGuidance: Result
        • RequestingGuidance: Result
        • TemporalityResult: Result[ ]
        • TopicRole: Result
  • TopTopics: TopicIntentionResult[ ]
    • OfferingGuidance: Result
    • Polarity: PolarityResult
      • Max: Result
      • Mean: Result
      • Min: Result
    • RequestingGuidance: Result
    • Topic: Result
    • TopicIntention: TopicActionTypeResult[ ]
      • ActionType: Result
      • TopicRoles: TopicRoleResult[ ]
        • Decisiveness: Result
        • OfferingGuidance: Result
        • RequestingGuidance: Result
        • TemporalityResult: Result[ ]
        • TopicRole: Result

Topics

Topics is very similar to TopicIntentions in complexity. As you may guess by now its type is TopicScorecard made up of these properties:

  • Domains: DomainResult[ ]
    • Domain: Result
    • Subdomains: SubdomainResult[ ]
      • Scores: Result[ ]
      • Subdomain: Result
  • Locations: Result[ ]
  • ProperNouns: TopicResult[ ]
    • OfferingGuidance: Result
    • Polarity: PolarityResult
      • Max: Result
      • Mean: Result
      • Min: Result
    • RequestingGuidance: Result
    • Topic: Result
  • TopTopics: TopicResult[ ]
    • OfferingGuidance: Result
    • Polarity: PolarityResult
      • Max: Result
      • Mean: Result
      • Min: Result
    • RequestingGuidance: Result
    • Topic: Result

I also promised to take a look at using the Search() method. When you use Search() you will need to put the terms into the “searchterms” parameter in the Param array that gets passed to Search(). The results that you receive will still come back as an AmplifyScorecard object.

Whew! Now, when working with these results it’s possible to use LINQ on the arrays. But on the whole, the “feel” of working with the SOAP results is a bit different from using the XDocument results that we got in Part 1 of this series.

Looking back at the Rat Catcher code I don’t think that it’s worth going back and switching it over to SOAP at this time, although I am considering it in the future. If I was using more “clever” LINQ statements leaving it as-is would be the best policy. In addition, my current strategy has the advantage of allowing me to easily store the XML for later retrieval, perhaps as a caching system. If I switched to SOAP I would need to write serialization code of some variety to be able to stick the results into storage. The tradeoff would be much cleaner code (since I would not be stepping through the Element properties of various parent elements) and possibly a slight performance increase due to eliminating the LINQ overhead.

In part five, I will be wrapping up this series with a discussion of the “business end” of OpenAmplify, in terms of where it fits into Rat Catcher’s overall functionality, my impressions of working with it and how integrating Rat Catcher with OpenAmplify has influenced Rat Catcher’s overall business model.

Catch up on previous installments

J.Ja