Build a C# Stock Quote WebService and Client using the
WebService Behavior HTC (Part I)

By Peter A. Bromberg, Ph.D.

Peter Bromberg

Spring is almost here, and it's time to create .NET stuff! So, building on my article of last year, "Build a Custom Stock Quote Component", I decided it would be a fun exercise to "stretch my skills" a bit and build a new one, but this time -- to do it in C# as a full-fledged .NET WebService. And, since Microsoft has been nice enough to give away a WebService Behavior HTC that can be "plugged in" to a DHTML web page to act as a webservice consumer, I thought that would be an elegant finishing touch to show an example of building a consumer Web page for my new StockQuote class. We'll deal with getting the WebService built and running in this installment, and in Part II, we review how to use the WebService DHTML Behavior in a regular client-side .htm page to consume the WebService. (The downloadable code link at the bottom of this article, however, contains ALL the code, 'cause I know how you hate to wait for people's "multiple part' articles!) In Part II, I'll get into some neat client-side stuff, so visit often.



On a side note, If you're in a quandary about DOT NET and you aren't sure whether to stay with VB6 or go to VB7 or start with C#, my advice is -- after a great deal of agonizing study and thought -- conserve all the extra time you can find, DROP EVERYTHING, and get started with C#. Forget VBScript (its already a dinosaur) as well as VB6 and even Javascript. Microsoft has over a million lines of C# code in the .NET platform - those guys are eating, breathing, sleeping and everything else in C#. And unlike their brethren at Oracle and Sun, they've submitted it to the ECMA for certification. In sum, C# is an elegant, simple, and powerful programming language that you're almost certain to see on other platforms while the Java guys who are still too busy bashing the guys in Redmond to see what's comin' at-em on the turnpike at 100 miles an hour will likely be wondering what happened.

In this article, we're going to walk through the Webservice C# code first, and then we'll take a look at the DHTML page and how the WebService Behavior can be used to easily wire up the page to act as a webservice consumer.

While this is a pretty simple class with only one method, "GetQuote" it still demonstrates some important techniques- handling and parsing multiple stock symbols as input parameters, utilizing the WebRequestFactory class, as well as the StreamReader and StringBuilder .NET classes to parse and clean up the response stream and process the return values.

Finally , we'll build a valid XML return document that the WebService returns to the calling client, as well some simple error -handling code.

If you don't have the full .NET Beta 1 Visual Sudio release, that's OK - you can build this stuff in Notepad and compile and run it just fine, as long as you've downloaded and installed the .NET Framework SDK.   I prefer the Visual Studio IDE for the Intellisense and all the cool access to servers, services, databases, and even Webservices (wherever in the world they may reside) which all get "wired up live" right into your IDE and can be brought in to one central location at your fingertips.  But sometimes it's nice to just whip out NotePad or EditPlus and start codin' (kind of like when your Commodore 64 used to come up with the blue screen saying "38632 BASIC BYTES FREE"-- man those were the days...).

First we need to start a new .asmx file because that's what tells the CLR (Common Language Runtime) that this is a Webservice. We start out by declaring our PageLanguage and starting class name, along with the CLR references that we'll need for the webservice:

<%@ WebService Language="C#" class="StockQuote" %>
using System ;
using System.Web.Services ;
using System.Net ;
using System.IO ;
using System.Text ;

Next we declare our public class "StockQuote" as a webservice, with the [WebMethod] directive:

public class StockQuote : WebService
{
[WebMethod]

Then we declare our public function and set up some required variables, along with the beginning of our try-catch block:

public string GetQuote(string symbol)
{
string result =null;
try
{
//URL to Yahoo spreadsheet format stock quote server...
string serverURL =@"http://quote.yahoo.com/d/quotes.csv?s="+symbol+"&f=sl1d1t1c1ohgvj1pp2owern&e=.csv"; 
char[] delim = {' '} ;
char[] delim2 = {','};
string[] symbols = symbol.Split(delim) ;
string sTemp=@"";
string sContentTemp=@"";
string sContentNew=@"";
string strChar="";

We then create a HttpWebRequest object for the stock URL:

HttpWebRequest webreq = (HttpWebRequest)WebRequestFactory.Create(serverURL);


-- and Retrieve HttpWebResponse object from the stock URL using the StreamReader object:


HttpWebResponse webresp = (HttpWebResponse)webreq.GetResponse();
StreamReader strm = new StreamReader(webresp.GetResponseStream(), Encoding.ASCII);

We then loop through each line from the stream, building our return XML Document string, but first we also "clean out" some of Yahoo's "noise" (quote) characters using the StringBuilder class:

StringBuilder strContent = new StringBuilder("");
sTemp+="<StockQuotes>";
for(int i=0;i<=symbols.GetLength(0)-1;i++){
sContentTemp = strm.ReadLine();
strContent.Append(sContentTemp);
for (int k=0;k<=strContent.Length-1;k++){
// remove the char from StringBuilder string if contains quite symbol ( \" )
if(strContent[k].ToString()=="\"" )
strContent.Remove(k,1);

}
// now should have clean string, create array of elements
string[] contents=strContent.ToString().Split(delim2);
// Clear out our StringBuilder for next iteration
strContent.Remove(0,strContent.Length);
sTemp+="<Stock>";
sTemp+="<Symbol>" +contents[0]+"</Symbol>";
sTemp+="<Last>" +contents[1]+"</Last>";
sTemp+="<Date>"+contents[2]+"</Date>";
sTemp+="<Time>"+contents[3]+"</Time>";
sTemp+="<Change>"+contents[4]+"</Change>";
sTemp+="<Open>"+contents[5]+"</Open>";
sTemp+="<High>"+contents[6]+"</High>";
sTemp+="<Low>"+contents[7]+"</Low>";
sTemp+="<Volume>"+contents[8]+"</Volume>";
sTemp+="<MktCap>"+contents[9]+"</MktCap>";
sTemp+="<PrevClose>"+contents[10]+"</PrevClose>";
sTemp+="<PctChg>"+contents[11]+"</PctChg>";
sTemp+="<AnnRange>"+contents[13]+"</AnnRange>";
sTemp+="<Earns>"+contents[14]+"</Earns>";
sTemp+="<P-E>"+contents[15]+"</P-E>";
sTemp+="<Name>"+contents[16]+"</Name>";
sTemp+="</Stock>";
result+=sTemp;
sTemp="";
}
//Close the stream from the server
strm.Close();
result +="</StockQuotes>";
}

Finally, we catch any exceptions, and return our result stream of valid XML (or "exception", as the case may be):

catch(Exception)
{
//If exception occurred, provide user message
result="exception";
}
//Return StockQuote(s) or Exception
return result ;
}
}

Now if you simply load this page in your browser, the .NET Platform will compile and cache it into IL (Intermediate Language) and you can see the default "Webservice Discovery Channel" page, as I like to call it. At this point, you should be able to pass the input parameters on the querystring, use a SOAP method call, or even use xmlHTTP to send the parameters to the service and get back the well-formed XML response document containing your quotes. Just be sure to delimit your quote symbols with spaces, as that's what Yahoo's server expects. Your StockQuote WebService class will take care of the rest. If you append "?SDL" to your URL to the service, you'll get a complete Service Description Language document that completely describes your webservice, its method(s), parameters and types.

My first example consumer page, which is included in the download Zip file, uses a separate XSLT stylesheet to transform the output to a nice HTML table. You can try out the online StockQuotes Webservice HERE.

I hope this gives you some ideas - its like Remote Data Services on steroids, without the security BS. Back to the Future!

Download the code that accompanies this article.

Peter Bromberg is an independent consultant specializing in distributed .NET solutionsa Senior Programmer / Analyst at in Orlando and a co-developer of the EggheadCafe.com developer website. He can be reached at pbromberg@yahoo.com