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!
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:
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:
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):
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...