In fact, since that time, the only thing the Weather Service has changed is that
they added a simple "Unit" parameter to the main method, which defaults
to "US-English". The only real remaining problem I saw was that the
webservice requires the Latitude and Longitude as input parameters.
There were a number of blog posts about it at that time and they all
had one theme: "I can't get it to work", "It times out",
etc. That's because it's in RPC format which pretty much reduces one to writing custom code to parse the returned XML. Mikhail Arkhipov of Microsoft actually did just that, providing a parser for the RPC results, an effort that still works today, some six years later.
Fortunately, I have a US ZipCode database that has the latitude and longitude for
every zipcode in the United States. So what I did was to export the SQL Server
Zipcode table to a flat file "ZIP CITY STATE LATITUDE LONGITUDE", delimited
with the pipe ( | ) symbol.
I then used QuickLzSharp to compress this and added it to the WeatherControl project
as an embedded resource.
Having extracted and decompressed the Text file of results from the assembly at runtime,
it was a simple matter to split it into rows and the rows into arrays and add
all this to a DataTable - which now allows you to create a Primary Key, perform
Select queries and all that cool stuff. So I now had a Zipcode database in an
assembly, and I wrote a nice ZipCode lookup component with the technique.
The code that gets the compressed resource looks like this, and includes the use
of the QuickLz Decompress extension method:
#region Resource Methods
private string GetDecompressedResourceString(string resource)
{
try
{
Assembly asm = Assembly.GetExecutingAssembly();
Stream stm=asm.GetManifestResourceStream(resource);
BinaryReader br = new BinaryReader(stm);
long siz = stm.Length;
byte[] bytInput =null;
bytInput=br.ReadBytes((int)siz);
string theResource =System.Text.Encoding.UTF8.GetString(bytInput.Decompress());
br.Close();
stm.Close();
return theResource;
}
catch(Exception ex)
{
throw new ApplicationException(ex.Message);
}
}
#endregion
Then I have the code for the control which uses this decompressed Zipcode.txt string:
#region ctor
public WeatherLookup()
{
this.IsDesignMode = (System.Web.HttpContext.Current == null);
if(IsDesignMode)return;
if(System.Web.HttpContext.Current.Cache["ZipCodeTable"]==null)
{
theZips = GetDecompressedResourceString("WeatherControl.Zipcodes.dat");
zipCodeTable.Columns.Add("zip", typeof(string));
zipCodeTable.Columns.Add( "city", typeof(string) );
zipCodeTable.Columns.Add( "state", typeof(string) );
zipCodeTable.Columns.Add( "Latitude", typeof(string) );
zipCodeTable.Columns.Add( "Longitude", typeof(string) );
// Set PrimaryKey
zipCodeTable.Columns[ "zip" ].Unique = true;
zipCodeTable.PrimaryKey = new DataColumn[] { zipCodeTable.Columns["zip"] };
string[] zippies = theZips.Split(new Char[] {'\r','\n'});
for (int i=0;i<zippies.Length;i++)
{
object[] theRow=zippies[i].Split(new Char[] {'|'});
if((string)theRow[0]!="")
zipCodeTable.Rows.Add( theRow);
}
zipCodeTable.AcceptChanges();
System.Web.HttpContext.Current.Cache["ZipCodeTable"]=zipCodeTable;
}
else
zipCodeTable =
(DataTable)System.Web.HttpContext.Current.Cache["ZipCodeTable"];
}
#endregion
Finally, I get my needed latitude and longitude from the DataTable by Zipcode:
private void FindLatitudeLongitudeByZipCode(string zip)
{
string strExpr;
strExpr = "zip='" +zip +"'";
// Use the Select method to find all rows matching the filter.
try
{
DataRow[] foundRows = zipCodeTable.Select(strExpr);
this.latitude=Convert.ToDecimal(foundRows[0].ItemArray[3]);
this.longitude = Convert.ToDecimal(foundRows[0].ItemArray[4]);
foundZip=foundRows[0].ItemArray[0].ToString();
foundCity=foundRows[0].ItemArray[1].ToString();
foundState=foundRows[0].ItemArray[2].ToString();
}
catch(Exception ex)
{
throw new Exception(ex.Message);
}
}
The rest of the code is simply standard Custom Control code to render the weather
service's returned information into a nice table, complete with the NOAA's
little pics for sunny, cloudy, etc.:

You can download the complete working Visual Studio 2010 solution here. This includes the Windows Forms Utility project to compress any file so that it
can be inserted into a project as an embedded resource.