When you think ASP, think...
Recent Articles
All Articles
ASP.NET Articles
ASPFAQs.com
Message Board
Related Web Technologies
User Tips!
Coding Tips
Search

Sections:
Book Reviews
Sample Chapters
Commonly Asked Message Board Questions
JavaScript Tutorials
MSDN Communities Hub
Official Docs
Security
Stump the SQL Guru!
Web Hosts
XML
Information:
Advertise
Feedback
Author an Article

ASP ASP.NET ASP FAQs Message Board Feedback
 
Print this Page!
Published: Wednesday, March 7, 2007

Updating the MultiDayForecast Web Control

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. To demonstrate using this service and Web services in general, I wrote an article titled Display Local Weather Forecasts with the NOAA's Web Service, in which we built a custom Web control named MultiDayForecast that displayed weather forecast information. The screen shot below shows this control in action.

The MultiDayForecast Control in action.

In the two years since the Display Local Weather Forecasts with the NOAA's Web Service article was authored, the NOAA has made a few breaking changes to their service, thereby breaking the MultiDayForecast control. I've since updated the MultiDayForecast control to handle these breaking chnages, as well as making it easier to handle future changes. This article details the NOAA's breaking changes and the steps taken to update the MultiDayForecast control. Read on to learn more!

- continued -

Breaking Change #1: An Update to the Web Service's Endpoint


When I first created the MultiDayForecast control, the WSDL document for the Web service (http://weather.gov/forecasts/xml/DWMLgen/wsdl/ndfdXML.wsdl) referenced the following endpoint as the URL for the Web service: http://weather.gov/forecasts/xml/SOAP_server/ndfdXMLserver.php. (The WSDL document provides the technical details for the Web service, including information like the service's endpoint (URL), the data type formats to be exchanged, low-level protocol information, and so forth. See An Extensive Examination of Web Services for background on Web services, WSDL, and other related technologies.)

However, since publishing the WSDL document, the Weather.gov website has since implemented some sort of URL rewriting rule that changes all requests that lack the "www" to redirects that include them. For example, if you visit http://weather.gov/forecasts/xml/DWMLgen/wsdl/ndfdXML.wsdl through a browser, note how the browser's Address bar is rewritten to: http://www.weather.gov/forecasts/xml/DWMLgen/wsdl/ndfdXML.wsdl. When visiting the URL without the "www", the website sends back an HTTP 301 response that indicates that the URL has been permanently moved to http://www.weather.gov/forecasts/xml/DWMLgen/wsdl/ndfdXML.wsdl. The browser receives this message and automatically requests the new URL (the one with the "www").

Unfortunately, the auto-generated proxy class used by the MultiDayForecast control isn't as smart as a browser. When it gets back the HTTP 301 response it freaks out because it was expecting a valid SOAP response. It therefore displays the response as an error, saying:

System.Net.WebException: The request failed with the error message: -- <!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN"> <html><head> <title>301 Moved Permanently</title> </head><body> <h1>Moved Permanently</h1> <p>The document has moved <a href="http://www.weather.gov/forecasts/xml/SOAP_server/ndfdXMLserver.php">here</a>.</p> <hr /> <address>Apache/2.0.46 (Red Hat) Server at weather.gov Port 80</address> </body></html> --.
In short, we need to update the proxy class to include the "www" in the URL.

Rather than just update the proxy class, we can instead update the code to more gracefully handle any future changes to the Web service's endpoint. To accommodate this, I updated the ForecastEngine class's GetDailyForecast method, which is the sole place the Web service is accessed from the control. Previously, I simply instantiated the proxy class and called the NDFDgenByDay method provided by the Web service. I've since updated the code to set the proxy class's Url property based on a setting in the Web application's Web.config file. If no such setting exists, it defaults to using http://www.weather.gov/forecasts/xml/SOAP_server/ndfdXMLserver.php.

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

// Read from the Web application's <appSettings> section
string wsUrl = System.Configuration.ConfigurationSettings.AppSettings["noaaWebServiceUrl"];

// If no setting is found in Web.config, use the default URL
if (wsUrl == null || wsUrl.Length == 0)
    wsUrl = "http://www.weather.gov/forecasts/xml/SOAP_server/ndfdXMLserver.php";

proxy.Url = wsUrl;

With this code in place, if there's any change to the NOAA's endpoint in the future, you can simply add the following <appSettings> entry to the Web application's Web.config file:

<configuration>
   <appSettings>
      <add key="noaaWebServiceUrl" value="url" />
   </appSettings>


   <system.web>
      ...
   </system.web>
</configuration>

See Specifying Configuration Settings in Web.config for more information.

Breaking Change #2: Handling Chunked HTTP Responses from the NOAA's Web Service


Since releasing the MultiDayForecast control, the NOAA made another change to their web server's configuration that resulted in a breaking change in the auto-generated proxy class used by MultiDayForecast. Specifically, they configured the web server to use chunked transfer encoding. As luck would have it, the proxy class doesn't like working with chunked transfer encoding and, in the face of such an encoding, will throw an HTTP protocol violation.

Rob Garrett noted this problem and provides a workaround in his blog entry, NOAA Weather Service and .NET. By default, the proxy class used by the MultiDayForecast control makes its HTTP request using HTTP 1.1, which supports chunked HTTP responses. HTTP 1.0, however, does not include support for chunked transfer encoding. Therefore, we can have the NOAA web server return non-chunked data by updating the proxy class to use HTTP version 1.0. When the NOAA's web server receives the HTTP request and sees it's version 1.0, it will not chunk the return data.

To have the proxy class to use HTTP 1.0 instead of 1.1, we need to override the proxy class's GetWebRequest method, which returns the HttpWebRequest used to issue to HTTP request to the Web service. The following code, taken from Rob's blog entry, shows the change we need to make:

protected override System.Net.WebRequest GetWebRequest(Uri uri)
{
   System.Net.HttpWebRequest request = (System.Net.HttpWebRequest) base.GetWebRequest(uri);
   request.ProtocolVersion = System.Net.HttpVersion.Version10;
   return request;
}

This code could be added to the auto-generated Reference.cs file in the Web References folder, but doing so would result in our customizations being lost the next time the proxy class was auto-generated. When extending auto-generated code use one of the following two approaches:

  • Use Inheritance - create a class that derives from the auto-generated class and add the additional properties/methods/etc. to this derived class. In your code, reference the derived class instead of the auto-generated one. This technique works equally well in ASP.NET 1.x and 2.0.
  • Use Partial Classes - partial classes are a feature new to .NET 2.0 and provide a way for a single class to be spread out across multiple files.
Since the MultiDayForecast control is an ASP.NET 1.x control, we will use inheritance. I created a class named ndfdXMLWithHTTP1Support that derived from ndfdXML, the auto-generated proxy class. I also put it in the same namespace as the auto-generated proxy class (WeatherInfo.gov.weather):

namespace WeatherInfo.gov.weather
{
   public class ndfdXMLWithHTTP1Support : ndfdXML
   {
      protected override System.Net.WebRequest GetWebRequest(Uri uri)
      {
         System.Net.HttpWebRequest request = (System.Net.HttpWebRequest)base.GetWebRequest(uri);
         request.ProtocolVersion = System.Net.HttpVersion.Version10;
         return request;
      }
   }
}

Lastly, we need to update the ForecastEngine class's GetDailyForecast to now use the ndfdXMLWithHTTP1Support class instead of ndfdXML:

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

...

Conclusion


Since its creation in March 2005, the MultiDayForecast control has encountered two hiccups due to breaking changes to the NOAA's weather forecast Web service. In particular, the Web service no longer allows URLs that lack the "www". When receiving such requests, the web server responds with an HTTP 301 response indicating the new URL to use. This non-SOAP response results causes the auto-generated proxy class to raise an exception. To fix this problem we needed to update the URL used by the proxy class to include the "www" portion.

The other breaking problem had to do with the Web service returning the SOAP response using chunked transfer encoding. Unfortunately, Microsoft's SOAP proxy class cannot correctly handle the chunked encoding and raises an exception. We can circumvent this by using the HTTP 1.0 protocol when making the Web service request. Since HTTP 1.0 does not support chunked transfer encoding, the Web service does not chunk its returned data and the proxy class can parse the content correctly.

Thanks to Rob Garrett, Martin Woods, and other alert 4Guys visitors who notified me of these problems and offerred suggestions and workarounds for fixing them...

Happy Programming!

By Scott Mitchell


Attachments


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


  • Display Local Weather Forecasts with the NOAA's Web Service
  • An Extensive Examination of Web Services
  • NOAA Weather Service and .NET


  • ASP.NET [1.x] [2.0] | ASPMessageboard.com | ASPFAQs.com | Advertise | Feedback | Author an Article