Wednesday, May 01, 2002

The SoapExtensionReflector type supports the .NET Framework infrastructure and is not intended to be used directly from your code. Microsoft really shouldn't put this note on classes in the .Net SDK documentation, it just makes me want to use those classes :-)

So System.Web.Services.Description.SoapExtensionReflector seems to be a pretty interesting class. SoapExtensionReflector can be subclassed and used to direct how the WSDL for your .NET web service gets created. SoapExtensionReflector defines a method called ReflectMethod which is called once for each WebMethod you've defined in your service. This is where you get the opportunity to modify the WSDL document (via the System.Web.Services.Description namespace classes) before it's serialized to XML. It seems like the default reflector has already been run at the point where your reflector gets called, so a lot of the heavy lifting has been done already, allowing you to concentrate on making specific modifications to the WSDL. To test this out, I wrote a simple attribute that allows you to import a description for an operation from an external document. This attribute takes a String which indicates the uri of the document you want to import:

[AttributeUsage(AttributeTargets.Method,AllowMultiple=false)] 
public class ExternalDocumentationAttribute : Attribute 
{  
 public ExternalDocumentationAttribute(String uri)  
 {  
  this.uri = uri;  
 }  
 public String DocumentationUri  
 {  
  get { return uri; }  
  set { uri = value; }  
 }  
 private String uri; 
} 

The documentation file is an XML file in the following format:

<documentation> 
This is the external documentation for my web method. 
</documentation> 

You apply the attribute to a web method like this:

[WebMethod,ExternalDocumentation("http://localhost/TestService/TestMethodDoc.xml")] 
public String TestMethod() 
{  
 return "Hello"; 
} 
I then created a custom reflector to look for the ExternalDocumentationAttribute, read the documentation from the specified location, and set the documentation attribute for the WSDL operation element:
public class XmlImportedElementReflector : SoapExtensionReflector 
{  
 public override void ReflectMethod()  
 {  
  ExternalDocumentationAttribute a =  
   (ExternalDocumentationAttribute) this.ReflectionContext.Method.GetCustomAttribute(
    typeof(ExternalDocumentationAttribute));  
  if (a != null)  
  {  
   Uri u = new Uri(a.DocumentationUri);  
   System.Net.WebRequest r = System.Net.HttpWebRequest.Create(u);  
   XmlTextReader reader = new XmlTextReader(  
    new System.IO.StreamReader(r.GetResponse().GetResponseStream()));  
   this.ReflectionContext.Operation.Documentation = reader.ReadElementString("documentation");  
   reader.Close();  
  }  
 } 
} 

The ReflectionContext property of the SoapExtensionReflector is where all the action is. ReflectionContext is of type System.Web.Services.Description.ProtocolReflector, also officially undocumented. ReflectionContext.Operation contains the definition of the operation element for the method currently being reflected. There's also a number of other properties that provide you with information about the WSDL information for the method currently being reflected, as well as information on other parts of the WSDL document. For example, you have access to the schema for the WSDL document, so you can modify the schema that gets reflected by your service, without using the attributes provided by the framework. Finally, I had to register my custom reflector in web.config. The type attribute on the add element is the full type name for the reflector, meaning that it consists of at least the namespace qualified type name followed by the assembly where the type is defined.

<configuration> 
 <system.web> 
  <webServices> 
   <soapExtensionReflectorTypes> 
    <add type="SerializationTest.XmlImportedElementReflector, SerializationTest" /> 
   </soapExtensionReflectorTypes> 
  </webServices> 
 </system.web> 
</configuration>

The end result of this is as I hoped; the operation element for the TestMethod web method has the external documentation appended. Even though the example is pretty simple, this seems like a really powerful way to modify the way ASP.Net generates the WSDL contract for your service. Looking at the little bits of documentation on ProtocolReflector, it seems like this class could be subclassed to provide some really powerful capabilities as well.

6:46:16 PM  permalink Click here to send an email to the editor of this weblog. 
A news release of some interest to me: Galileo Travels Down Web Services Path: The preeminent distributor of fare and booking information for the travel industry is deconstructing its entrenched applications, such as those for handling airline fare inquiries and ticket booking, into Web services components with interfaces based on Simple Object Access Protocol (SOAP). The intent is to turn what is today a one-size-fits-all approach to dispensing travel information into a pliable environment where customers can stitch together Web services components into customized applications that can be accessed from any platform.
6:46:10 PM  permalink Click here to send an email to the editor of this weblog. 


Stories
DateTitle
1/23/2003 Why XML?
8/13/2002 Resolution for IE and Windows problems
8/10/2002 Supporting VS.NET and NAnt
5/11/2002 When do you stop unit testing?
Contact
jabber: weakliem
YM: gweakliem
MSN: gweakliem@pcisys.net
email: Click here to send an email to the editor of this weblog.
Subscribe to "Gordon Weakliem's Weblog" in Radio UserLand.
Click to see the XML version of this web page.