TheChaseMan's Frenetic SoapBox

Always looking for better ways to do things...

Contract First: Why are messages being translated into NULL objects in VS2005?

It's been a while since I've blogged about something I would classify as "interesting." I plan on revising some earlier posts I've made about WPF and LINQ in the near future using latest bits.

But I digress...

The reason I'm posting today is to share a resolution to a problem I ran into using the same contract-first approach to creating a Web Service in Visual Studio 2005 that I used to have no problems doing in Visual Studio 2003. My messages going to or from my WebMethod end up translated into objects that contain null references in Visual Studio 2005! Oh no! What did I do wrong? This same process worked very well using Visual Studio 2003. What gives? Let's reproduce the problem...

So, let's say you are following the contract-first rules and you decide to create a schema for your request and response messages for a WebMethod. In fact, to make it simple, let's just create a response schema for a WebMethod that has no input message.

<xs:element name="FooResponse">
  
<xs:complexType>
     <
xs:sequence>
       <
xs:element name="Bar" type="xs:string" />
    
</xs:sequence>
   </
xs:complexType>
 </
xs:element>
 

Using Visual Studio 2003 command prompt, I run the "xsd.exe /c" command against my schema and end up with a class that looks something like the following:

[System.Xml.Serialization.XmlTypeAttribute(Namespace="http://tempuri.org/XSDSchema1.xsd")]
[System.Xml.Serialization.XmlRootAttribute(Namespace="http://tempuri.org/XSDSchema1.xsd", IsNullable=false)]
public class FooResponse {
    public string Bar;
}

Now I can create a WebMethod create a FooResponse and return it to the caller...

[WebMethod]
[SoapDocumentMethod(ParameterStyle = SoapParameterStyle.Bare)]
[return: XmlElement("FooResponse")]
public FooResponse GetFoo() {
    FooResponse foo = new FooResponse();
    foo.Bar = "bar";
    return foo;
}

Using Visual Studio 2003 or Visual Studio 2005, I create a client to call the Web Service and write the results out to a console...

Status webService = new Status();
FooResponse r = webService.GetFoo();
XmlSerializer ser = new XmlSerializer(typeof(FooResponse));
ser.Serialize(Console.Out, r);

No shock here, it works like a champ! Here is the console output..

<?xml version="1.0" encoding="IBM437"?>
<FooResponse xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Bar xmlns="http://tempuri.org/XMLSchema1.xsd">bar</Bar>

 

But...let's take this same XSD and use the "xsd.exe /c" command from the Visual Studio 2005 command prompt and create the same Web Service in Visaul Studio 2005. The WebMethod on the server and the client code will be exactly the same. The difference will be in the class generated from the XSD.

[System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "2.0.50727.42")]
[System.SerializableAttribute()]
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
[System.Xml.Serialization.XmlTypeAttribute(AnonymousType=true)]
[System.Xml.Serialization.XmlRootAttribute(Namespace="http://tempuri.org/XMLSchema1.xsd", IsNullable=false)]
public partial class FooResponse {   
    private string barField;

    public string Bar {
        get { return this.barField; }
        set { this.barField = value; }
    }
}

Well, there seems to be a few more attributes decorating this class and Bar is now defined as a property instead of a field, but let's push forward and try to run the app.

<?xml version="1.0" encoding="IBM437"?>
<FooResponse xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" />

"Ruh Roh Raggy - it no worky!!!!" says Scooby Doo. Where did Bar go???????

Admittedly, it took me about an hour to find this problem using a much more complex schema. Immediately false assumptions about the schema being incorrect, IIS configuration problem, namespace issues, and all kinds of other stuff started going through my head. Finally, I flipped a bit in the class generated by "xsd.exe /c" and everything started working:

[System.Xml.Serialization.XmlTypeAttribute(AnonymousType=false)]

Maybe not rocket science, but hopefully this blog post was "interesting" and/or saves some other poor SOB developer some time in the future.  :-)

PS. Don't forget to update your Web Reference on your client app after you alter this code on the server should you decide to play around with my example. Enjoy!


Digg!

posted on Thursday, October 12, 2006 11:09 AM

Feedback

No comments posted yet.