To read the article online, visit http://www.4GuysFromRolla.com/articles/030205-1.aspx

Display Local Weather Forecasts with the NOAA's Web Service

By Scott Mitchell


Introduction


In December 2004 the National Oceanic and Atmosphere Administration (NOAA) unveiled a Web service for accessing weather forecasts for locations within the United States. The Web service provides two methods:
  • NDFDgen(latitude, longitude, detailLevel, startTime, endTime, weatherParametersToReturn) - returns a range of weather information for a particular latitude and longitude between a start and end time. The weatherParametersToReturn input parameter dictates what weather information should be returned, such as: maximum temperature, minimum temperature, three hour temperature, snowfall amount, wind speed, and so on.
  • NDFDgenByDay(latitude, longitude, hourlyFormat, startDate, numberOfDays) - returns 12-hour or 24-hour weather information for a particular latitude/longitude starting from a certain date and extending a specified number of dates into the future.
Assuming the latitude and longitude are in the NOAA's database, the Web service returns an XML document that contains a variety of weather information for the dates specified, based on the parameters passed into the Web service. (For more detailed information on the NOAA's Web service, refer to http://www.nws.noaa.gov/forecasts/xml/.)

When reading up on this new Web service, I stumbled across Mikhail Arkhipov's blog entry titled Weather Forecast ASP.NET User Control, which provides a User Control written in C# for displaying the seven-day forecast for a particular latitude and longitude. While Mikhail's User Control definitely fit the bill for a simple forecast display in a C# Web application, I was tempted to provide similar functionality in a custom, compiled server control, which would allow the weather forecasts to be displayed in VB.NET Web applications as well. Additionally, I wanted to add some additional customization not found in Mikhail's solution.

The remainder of this article examines my custom control, MultiDayForecast (see screenshot below). We'll look at creating the proxy class for calling the Web service, techniques used to enhance the performance, how to customize the appearance of the MultiDayForecast control, and see how to use MultiDayForecast in an ASP.NET page. (If you are just interested in seeing how to use the MultiDayForecast control on an ASP.NET page and do not care to learn how the control works underneath the covers, feel free to skip to the Using MultiDayForecast in an ASP.NET Page section.) Read on to learn more!

Utilizing the NOAA's Web Service


In order to display a forecast to an end user, we first need to access the weather information for a particular latitude and longitude through the NOAA's Web service. As discussed in An Extensive Examination of Web Services, calling a Web service from a client application is a trivial task thanks to the concept of proxy classes. A proxy class is class that is auto-generated from the Web service's Web Service Description Language (WSDL) contract, encapsulating the complexity in calling the Web service. The proxy class provides the same set of methods as the Web service and these methods, when called by the client, do all of the hard work involved in invoking a Web service (formatting the call into a SOAP request, making an HTTP request to the Web service, retrieving and parsing the HTTP response, and returning a value to the client application). (This article does not intend to discuss Web services in-depth; be sure to consult An Extensive Examination of Web Services for more information on the fundamentals of Web services.)

To create a proxy class, simply add a Web Reference (from Visual Studio .NET, right-click on References and select Add Web Reference). In the Add Web Reference dialog box, enter the URL to the NOAA's Web service's WSDL document - http://weather.gov/forecasts/xml/DWMLgen/wsdl/ndfdXML.wsdl. The generated proxy class will have two methods: NDFDgen() and NDFDgenByDay(). (The MultiDayForecast control uses the latter method to get forecast information for a specified number of days.)

Unfortunately the Web service's methods both return an XML string as their result. This means that upon calling these methods, we'll need to programmatically parse the XML data to pick out the particular bits of interest. To accomplish this I use an XmlDocument object with XPath expressions to snip out the pieces of interest. (For more on XPath be sure to read this FAQ as well as the W3Schools XPath Tutorial.)

The data extracted from the XML document is stored in the DayWeatherData class I created, which has properties for each of the bits from the weather forecast that can be shown in the MultiDayForecast control:

  • DateTime - the date of the weather forecast
  • LowTempF - the forecasted low temperature for the day, in Fahrenheit
  • LowTempC - the forecasted low temperature for the day, in Celsius (a read-only property; computed from the LowTempF property)
  • HighTempF - the forecasted high temperature for the day, in Fahrenheit
  • HighTempC - the forecasted high temperature for the day, in Celsius (a read-only property; computed from the HighTempF property)
  • CloudIconURL - the icon to use to display the day's conditions. (The NOAA's Web service provides a standard set of 55x58 sized JPEG images for differing weather conditions. The XML data returned provides URLs to these images for each day.)
The following code illustrates how the NOAA's Web service is called and its data populated into an array of DayWeatherData instances.

// Create the proxy class
gov.weather.ndfdXML proxy = new gov.weather.ndfdXML();

// Retrieve the XML data for a specified latitude/longitude,
//  start date, and number of days to forecast.
string xmlData = proxy.NDFDgenByDay(latitude, longitude, 
                           startDate, numDays.ToString(), 
                           gov.weather.formatType.Item24hourly);

// load up the XML data...
XmlDocument doc = new XmlDocument();
doc.LoadXml(xmlData);

// read in the data
XmlNodeList highs = doc.SelectNodes(XPath Expression);
XmlNodeList lows = doc.SelectNodes(XPath Expression);
XmlNodeList cloudIcon = doc.SelectNodes(XPath Expression);

// create a DayWeatherData instance for each result
DayWeatherData [] forecastData = new DayWeatherData[numDays];

// Populate the array of DayWeatherData instances with the
// results returned in the XML payload...
for (int i = 0; i < numDays; i++)
{
   forecastData[i] = new DayWeatherData();
   forecastData[i].HighTempF = 
       highs[i] != null ? highs[i].Value : string.Empty;
   forecastData[i].LowTempF = 
       lows[i] != null ? lows[i].Value : string.Empty;
   forecastData[i].CloudIconURL = 
       cloudIcon[i] != null ? cloudIcon[i].Value : string.Empty;
   forecastData[i].DateTime = startDate.AddDays(i);
}

Enhancing the Performance of MultiDayForecast


In my initial design, when MultiDayForecast exists on an ASP.NET page, every time the page was loaded - be it on the first visit to the page for a user or on a postback - the MultiDayForecast control made a request out to the NOAA's Web service. In my tests, the NOAA's Web service was usually pretty responsive, but sometimes it could take several seconds to receive a response from the Web service, which therefore had the effect of having the page hang.

Since 24-hour weather forecasts don't change that often and since the data can be shared among multiple users, the weather data is a prime candidate for caching. I decided to cache the XML string returned by the call to the Web service for a period of two hours. Therefore, if the cache does not contain the XML results from the Web service, the Web service will be invoked and the response added to the cache. Otherwise, if the response is found in the cache, the Web service call can be bypassed. This greatly improves performance and amortizes the cost of the Web service call across the users accessing the site.

Shown below is the code that caches the XML results. This code is a modified version of the code we examined in the last code block.

// see if we have this data in the cache
string cacheKey = 
             string.Format("ForecastEngine-{0}-{1}-{2}-{3}", 
             latitude.ToString(), longitude.ToString(), 
             startDate.ToShortDateString(), numDays.ToString());
string xmlData = HttpContext.Current.Cache[cacheKey] as string;

if (xmlData == null)
{
   // data is not in the cache, call the Web service...
   gov.weather.ndfdXML proxy = new gov.weather.ndfdXML();
   xmlData = proxy.NDFDgenByDay(...);

   // add forecastData to the cache for two hours
   HttpContext.Current.Cache.Insert(cacheKey, xmlData, 
              null, DateTime.Now.AddHours(2.0), TimeSpan.Zero);
}

// load up the XML data...
XmlDocument doc = new XmlDocument();
doc.LoadXml(xmlData);

... The remainder of the code is identical to the code snippet above ...

Notice that the XML data is cached using the cacheKey variable, which is a combination of the latitude, longitude, start date, and number of days to forecast. This combination of variables was used in constructing the cacheKey so that different instances of the MultiDayForecast control on the site using different latitudes/longitudes, start date, or days to forecast can each have their own cached copy of the results.

Using MultiDayForecast in an ASP.NET Page


To use the MultiDayForecast control in an ASP.NET page you'll first need to download the control's code and/or compiled assembly, which are available at the end of this article. If your Web site is running ASP.NET 1.1 (that is, if you are using Visual Studio .NET 2003), then you can simply save the compiled assembly (WeatherInfo.dll) to your computer and add it to the Visual Studio .NET Toolbox. (To add an item to the Toolbox, right-click on the Toolbox and choose Add/Remove Items (in VS.NET 2002 it will be Customize Toolbox). Then Browse to the assembly and click OK. This should add an item to your Toolbox named MultiDayForecast.) If you are running ASP.NET 1.0 you will need to create a new project in Visual Studio 2002 and manually add the .cs files from the download and build the project. This will result in a compiled assembly, WeatherInfo.dll, which you can then add to the Toolbox using the steps discussed earlier.

Once you have the MultiDayForecast in the Toolbox, you should be able to simply drag and drop it onto an ASP.NET page's Design view. The screenshot to the right shows the MultiDayForecast control after it has been added to an ASP.NET page.

The following MultiDayForecast properties are the ones that are responsible what data to request from the NOAA's Web service:

  • Latitude - the latitude of the location. Must be within the NOAA's database, which is limited to the United States. Defaults to 32.7452, the latitude of San Diego, CA.
  • Longitude - the longitude of the location. Must be within the NOAA's database, which is limited to the United States. Defaults to -117.1979, the longitude of San Diego, CA.
  • DaysToForecast - the number of days to forecast. Defaults to 5.
  • StartDate - the starting date of the forecast; defaults to the current date. This property cannot be set through the Properties pane and likely shouldn't ever be specified (either declaratively or programmatically), unless you want the forecast for a particular date instead of the current date.)
By default, the MultiDayForecast will display the five day forecast for San Diego, California. You will need to tweak the Latitude and Longitude property values to get the forecast for your area. You can find latitude and longitude coordinates for various cities by searching on Google.

Customizing the Appearance of MultiDayForecast


The MultiDayForecast control has a number of properties that can be used to customize the appearance of the forecast in the end user's browser:
  • ForecastLayout - indicates if the weather forecast is laid out horizontally or vertically.
  • HeaderText - the text to display atop the forecast; defaults to "Weather Forecast". (The text is only displayed if ShowHeader is true (the default).)
  • DailyForecastStyle, DateStyle, CloudStyle, HiTempStyle, LowTempStyle - style information dictating how the each day's forecast is displayed, how the date in the forecast is displayed, how the weather conditions image is displayed, how the high temperature is displayed, and how the low temperature is displayed.
  • DateFormatString - the format string to use when displaying the forecast's date. Defaults to "D", which is a long date (i.e., Monthname, Day, Year).
These style properties can be set through the Visual Studio .NET Properties pane and their values are reflected immediately in the WYSIWYG designer. The following declarative syntax shows how to customize the appearance of the MultiDayForecast control to have the look and feel shown in the first screenshot at the top of this article:

<cc1:multidayforecast id="MultiDayForecast1" runat="server"
	Font-Names="Arial" Font-Size="X-Small" BackColor="#E0E0E0" 
	DateFormatString="dddd, MMMM d" 
	HeaderText="Weather Forecast for San Diego, CA">
	  <DateStyle Font-Bold="True" HorizontalAlign="Center"></DateStyle>
	  <HeaderStyle Font-Size="Medium" Font-Bold="True" 
	         HorizontalAlign="Center" BackColor="#FFFFC0"></HeaderStyle>
	  <CloudStyle HorizontalAlign="Center"></CloudStyle>
	  <HiTempStyle HorizontalAlign="Center" 
	                        ForeColor="Red"></HiTempStyle>
	  <LowTempStyle HorizontalAlign="Center" 
	                        ForeColor="Navy"></LowTempStyle>
</cc1:multidayforecast>

Conclusion


In this article we examined the MultiDayForecast control, a compiled, custom server control that utilizes the NOAA's Web service to display a weather forecast for a particular location within the United States. This control can be used in an ASP.NET Web page by simply dragging and dropping from the Toolbox onto the designer.

The MultiDayForecast control is completely functional at this point but could use a few improvements, which I intend to do in a later article. My tentative list of improvements include:

  • The ability to specify a timeout so if the NOAA's Web service takes too long to respond, the control will sever the request so as not to hang the requested ASP.NET page.
  • Finer tuned exception handling. Right now, if an exception occurs when requesting the Web service's data, a simple, "We're having problems"-type message is displayed. Ideally there would be a way to provide a page developer with richer information about the exception, but not dump a technical error message to the end user.
It would also be awesome to be able to accept zip codes as opposed to latitude and longitude inputs. If anyone knows of a free zip code to latitude/longitude Web service, let me know!

Happy Programming!

  • By Scott Mitchell


    Attachments


  • Download the complete source code (in ZIP format)
  • Further Readings


  • Updating the MultiDayForecast Web Control
  • An Extensive Examination of Web Services
  • Article Information
    Article Title: ASP.NET.Display Local Weather Forecasts with the NOAA's Web Service
    Article Author: Scott Mitchell
    Published Date: March 2, 2005
    Article URL: http://www.4GuysFromRolla.com/articles/030205-1.aspx


    Copyright 2017 QuinStreet Inc. All Rights Reserved.
    Legal Notices, Licensing, Permissions, Privacy Policy.
    Advertise | Newsletters | E-mail Offers