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!