This article targets: TIBCO Spotfire 2.0 and forward
Introduction
If you have ever written a piece of .NET code that deals with network communication, I bet that you recognize the following snippet. You may even have written something similar yourself. Although the code works fine in your regular .NET applications, this article will highlight the dangers of it when run in the context of TIBCO Spotfire extensions.
HttpWebRequest request = (HttpWebRequest) WebRequest.Create("http://stn.spotfire.com");
HttpWebResponse response = (HttpWebResponse) request.GetResponseStream();
Explaining the WebRequest Class
First, let me explain what the lines of code in the snippet above really do. The method WebRequest.Create(…) is a factory method for subclasses to WebRequest. Which class you obtain an instance of when you call the method, depends on the URI you pass to it. For instance, A URI that starts with http:// will result in an object of type HttpWebRequest whereas ftp:// will give you an instance of class FtpWebRequest. What Microsoft doesn’t normally tell you, is that this framework is extendible. This allows anyone to plug in code to handle new protocols beside HTTP and FTP or, better yet, plug out existing code and replace it with new (e.g. to provide a new implementations for HTTP web requests).
The Spotfire HTTP Client
As of version 2.0, TIBCO Spotfire bundles its own HTTP client for server communications. The new client is based on the same code as Internet Explorer, which means that:
- its prerequisites are built into the operating system,
- it is built on top of a component that is well tested,
- it is easy to configure (e.g. proxy server settings, HTTPS certificates, cookie handling, etc.),
- and last, but definitely not least, it is very fault tolerant (e.g. for slow or shaky network connections).
All in all the HTTP client has much better quality than the one built into the .NET framework.
The Spotfire HTTP client is injected into the .NET framework using the approach explained in the previous section. This means that using it is completely transparent. Whenever a call is made to WebRequest.Create(…) with a HTTP or HTTPS URL, as opposed to creating an instance of the standard HttpWebRequest .NET class, the Spotfire web request implementation is created. Of course, a consequence of this is that all code that expects the Create method to return an instance of HttpWebRequest (by casting to it) will fail with a ClassCastException. This is a big problem since all of Microsoft’s code examples revolving around HTTP communication advocate the cast.
How to Post Data
So, assume we are writing a Spotfire extension that needs to make calls to an external web service to retrieve or post some data. How would you go about and do this the right way?
Here is a code snippet that illustrates a Tool doing an HTTP POST to a web server.
public class CommunicationsTool : CustomTool<AnalysisApplication>
{
public CommunicationsTool() : base("Search Yahoo")
{
// Empty
}
protected override void ExecuteCore(AnalysisApplication context)
{
string query = "p=spotfire";
WebRequest request = WebRequest.Create("http://search.yahoo.com/search");
request.Method = "POST";
using (Stream s = request.GetRequestStream())
{
byte[] data = Encoding.UTF8.GetBytes(query);
s.Write(data, 0, data.Length);
}
// NOTE: We don’t have to set the ContentLength property on the
// request. That is automatically calculated by the client. In fact,
// attempting to set it will throw an exception.
WebResponse response = request.GetResponse();
using (StreamReader r = new StreamReader(response.GetResponseStream()))
{
Trace.WriteLine(r.ReadToEnd());
}
}
}
Using WebClient
Here a simple rewrite of the ExecuteCore method that uses the .NET WebClient to download a file. As the WebClient is written on top of the WebRequest class, it too will use the Spotfire HTTP client.
protected override void ExecuteCore(AnalysisApplication context)
{
WebClient c = new WebClient();
c.DownloadFile("http://stn.spotfire.com/stn/Images/first.png", "c:\\first.png");
}
Limitations
In its current implementation, the Spotfire HTTP client has one minor limitation that is good to be aware of, namely that it does not support asynchronous operations. That is, you are not allowed to use any of the Begin… and End… methods (e.g. BeginGetResponse) that the WebRequest base class defines. In practice this is not that big of a deal, since you always can use the .NET ThreadPool or a Thread to spin off the communication in a parallel thread and hence avoid hanging the main thread of your application while you wait for the response to get back.
Conclusions
To conclude, always remember that whenever you attempt to communicate over HTTP within TIBCO Spotfire, you will be doing it using a much more stable HTTP client than what is provided out-of-the-box in .NET.
Also, I hope I have given you a good example of why hard casting of types always is a bad idea.