Category: Uncategorized

When Web Services Go Bad

By , January 2, 2012

A few years ago I published a number of articles around using the National Weather Service NDFD web service to get current weather conditions and forecasts.  Unfortunately a few months ago quite a few folks started mentioning the example applications had stopped working.  I finally got time to look at the problem and have updated both the original articles and download examples.  Just to tidy things up – and so folks won’t have to wait next time, I thought I would describe how I got everything working again.  I’ll walk through the simplest example (the one from the “Consuming NDFD Web Services from a C# Client” post, but the debugging process and changes apply to all the examples that access the NDFD web service.

InvalidZipCode

 

1.  First I ran the original NdfdTest-Application example from the post.  Yes, things weren’t looking so good.

 

 

 

 

2. So I downloaded and built the original project – and there were errors:

badbuild

Clearly the service reference for the NDFD web service was not getting created.

 

3. Visual Studio can update service references if you ask so I right-clicked on the NdfdServiceReference and selected “Update Service Reference” from the shortcut menu and built the project again:

badcomplile2

Ah ha!  [Change 1] They changed the signature of the method used to get forecasts!  To see what’s happened, double click on the NdfdServiceReference from the Solution Explorer in Visual Studio then expand the NdfdTest.NdfdServiceReference node in the Object Browser and click on the ndfdXMLPortType interface.  It turns out they changed the signatures for all the methods, adding the ability to specify whether you want results in English (unitType.e) or Metric (unitType.m) units.  So I modified the NDFDgetByDay function, adding a unitType.e parameter and ran the application – and we are still getting an Invalid Zip Code error.  But now you can see in the output window we are getting a protocol exception:

exception

 

4. This is good information, but not enough.  So in Visual Studio I enabled breaking on any thrown Common Language Runtime Exception.  I ran the application again, entered a zip code and bang!

protocolexception

What the heck is going on?  We asked for for text/xml and we are getting text/html.

[Change 2] Somebody moved our web service – now it’s a web page instead!

webpage

 

5. I admit at this point, as soon as I updated the service reference, I should have gone to the app.config file and looked at what was generated for me.  Well, never too late…  Low and behold, there is a new address for the NDFD web service:

address

When I wrote this series of posts, the NDFD web service was at http://www.weather.gov.  Now it’s at http://graphical.weather.gov instead.

6. So finally, replace the address on our original ndfdXMLPort endpoint with the address from the newly generated ndfdXMLPort1 endpoint.  Everything is working again.

Consuming NDFD Web Services from a C# Client

By , August 12, 2009

[January 2, 2012 Update: A number of changes have been made to the NDFD web service since I originally posted this article. Both the URL and the methods exposed by the service have changed. The text below and downloads have been updated to reflect these changes.]

I like to know what the weather is going to be – it sets the tone for the day. But it is getting more difficult to get access to weather forecasts from the local television stations. Clearly lots of folks must tune in just for the weather because there seem to be this cat-and-mouse game where they parcel out snippets of info with “My complete forecast” always happening some time later…

National Weather Service to the rescue. They have a nice web site where you can get your local 7-day forecast (updated hourly). But what’s even more interesting, if you click around on the map you can get a forecast for anywhere in the US, even for places that aren’t even close to a NWS field office (this keeps getting better and better) and all this data is available from a SOAP-based web service, the National Digital Forecast Database (NDFD). So it looks like there is a way to get weather forecasts– and I don’t have to wait for the “News at 5”. And I can stick them in a desktop Gadget, in a Word document or on a PowerPoint slide.

The NWS provides a WSDL document so you might think it would be a simple thing to add a Service Reference to your project, have a proxy automatically generated, and you’re ready to roll. But unfortunately there is a wrinkle. The app.config file that’s auto generated from the NDFD WSDL document specifies that we’re going to use the stock basicHttpBinding and every time you send a SOAP request to the service you see this:

System.ServiceModel.ProtocolException was unhandled. Message=”The content type text/xml; charset=ISO-8859-1 of the response message does not match the content type of the binding (text/xml; charset=utf-8). If using a custom encoder, be sure that the IsContentTypeSupported method is implemented properly.

In this case, the problem really doesn’t have anything to do with correctly implementing IsContentTypeSupported. It’s caused by the fact that the NDFD service uses ISO-8859-1 encoding. However the MessageEncoder used by the basicHttpBinding only understands UTF-8, UTF-16 and Big-Endian Unicode… So finally there’s an excuse to create a custom binding. And the good news is that although this might be tedious, it’s not hard and there is a Microsoft sample that does exactly what we need. Instead of using the “optimized” XML reader and writer used by WCF, the sample uses a plain ole System.Xml.XmlReader and System.Xml.XmlWriter which do support ISO-8859-1. So aside from having to add a custom MessageEncoder, MessageEncoderFactory, MessageEncodingBindingElement and BindingElementExtensionElement to our project (just cut and paste from the Microsoft sample), things really aren’t too bad.

Once the custom MessageEncoder (and friends) are in place we still need to modify the auto-generated system.ServiceModel section of our app.config file (actually, in this case we’re going to just replace the whole section). Here is what it looks like:

  <system.serviceModel>
    <bindings>
      <customBinding>
        <binding name="DefaultBinding">
          <StmEncoding messageVersion="Soap11" encoding="ISO-8859-1" />
          <httpTransport />
        </binding>
      </customBinding>
    </bindings>
 
    <client>
      <endpoint address="http://graphical.weather.gov/xml/SOAP_server/ndfdXMLserver.php"
                      binding="customBinding" bindingConfiguration="DefaultBinding"
                      contract="NdfdServiceReference.ndfdXMLPortType"
                      name="ndfdXMLPort" />
    </client>
 
    <extensions>
      <bindingElementExtensions>
        <add name="StmEncoding"
                 type="StmEncoderLibrary.StmEncoderBindingElementExtensionElement,
                           StmEncoderLibrary"/>
      </bindingElementExtensions>
    </extensions>
 
  </system.serviceModel>

The first thing required is a new endpoint.

      <endpoint address="http://graphical.weather.gov/xml/SOAP_server/ndfdXMLserver.php"
                      binding="customBinding" bindingConfiguration="DefaultBinding"
                      contract="NdfdServiceReference.ndfdXMLPortType" 
                      name="ndfdXMLPort" />

The address and contract are the same ones that were auto-generated from the NDFD WSDL document, but instead of using a basicHttpBinding, we specify a customBinding which gives us complete control of the WCF messaging stack. The specific custom binding we’re going to use in this case is named “NdfdBinding”. The name of the endpoint is how we are going to reference this endpoint when we create the service proxy in our application.

The next piece is the customBinding.

      <customBinding>
        <binding name="DefaultBinding">
          <StmEncoding messageVersion="Soap11" encoding="ISO-8859-1" />
          <httpTransport />
        </binding>
      </customBinding>

You probably don’t recognize the StmEncoding element (neither does Visual Studio IntelliSense). It’s a custom element that references a binding extension – this is how our custom MessageEncoder implementation gets into the act. Note that StmEncoding has messageVersion and encoding attributes – this is where we specify now our encoder is going to work – they are the values that eventually get passed to our custom MessageEncoderFactory and then to our custom MessageEncoder constructor.

Finally the bindingExtension:

      <bindingElementExtensions>
        <add name="StmEncoding"
                 type="StmEncoderLibrary.StmEncoderBindingElementExtensionElement,
                           StmEncoderLibrary"/>
      </bindingElementExtensions>

This is where we specify the fully-qualified name of our class derived from BindingElementExtensionElement and the assembly containing the entire custom message encoder implementation.

Well, that’s it. Once you have the custom MessageEncoder that handles ISO-8859-1 and an appropriately constructed app.config file you should be able to talk to the NDFD web service and get a weather forecast whenever you want.

If you would like try out the code, here is a working version of a Windows Forms application and a dll containing a custom MessageEncoder, and here is the source code.

Next I think I’ll make the XML data a bit more readable.

Panorama Theme by Themocracy