Control WSDL types section

51 views
Skip to first unread message

Armando Garcia

unread,
Aug 27, 2002, 4:09:55 PM8/27/02
to
How can I specify the the minoccur/maxoccur of elements at
the schema generated at the WSDL?

Say, if I have a simple field:
Public aString As String

it is being shown on WSDL as:
<s:element minOccurs="0" maxOccurs="1"
name="aString" type="s:string" />

but what if want to make this element mandatory
(minOccurs="1")

The same thing happens for arrays, say:
Public someStrings() As String

in the WSDL it will become a complex type but in the
definition it will show an unbounded at the maxOccurs.

I guess that the idea of having the types section at WSDL
is to fully specify what the service provider expects from
its clients. Now, how do I make sure that the WSDL tells
what do I need?

Adrian Turtschi

unread,
Sep 1, 2002, 2:58:19 PM9/1/02
to
First, you should probably ask yourself:
(i) do I really need to fiddle with the minOccurs/maxOccurs attribute?
(ii) why don't I just use a static WSDL file for my Web service (with the
"massaged" attributes)

However, if you still want to dynamically create WSDL files (using the
http://localhost/vDir/myService.asmx?WSDL) with your own minOccurs values,
here's how to do it:
(A) Create a new System.Attribute that allows you to specify in your Web
method for which in-parameters you want to change the minOccurs attribute in
the WSDL types section.
(B) Create a new SoapExtensionReflector that will change the WSDL generated
by ASP.NET. You need to override one method: ReflectMethod(). You can get at
the WSDL Types information by using
ReflectionContext.ServiceDescription.Types. Massage your type, and write
your changes back.
(C) Register your SoapExtensionReflector in web.config

Here's a concrete example:

(C) web.config: add

<system.web>
<webServices>
<soapExtensionReflectorTypes>
<add type="wsdlModify1.customSoapExtensionReflector, wsdlModify1" />
</soapExtensionReflectorTypes>
</webServices>
<system.web>

(A) and (B): I have a sample Web service, wsdlModifiy1.Service1, with one
Web method, wsdlModify1.testMethod(...). This method has three arguments,
myArg1 through myArg3. I define an Attribute changeMinOccurs to change the
minOccurs value for a particular in-parameter. In my example, I use this
attribute twice because I want to change the first two in-parameters. All
the actual work is being done in the SoapExtensionReflector
wsdlModify1.customSoapExtensionReflector

using System;
using System.IO;
using System.Text;
using System.Collections;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Web;
using System.Web.Services;
using System.Web.Services.Protocols;
using System.Web.Services.Description;
using System.Xml;
using System.Xml.Schema;
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
~~~~~~~~~~~~~~
// public webService wsdlModify1.service1
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
~~~~~~~~~~~~~~
/// <summary>
/// The public wsdlModify1.service1 Web service demonstrates using
/// SoapExtensionReflector to change the WSDL <types> section
/// </summary>
///
/// <remarks>
/// <author dev="Adrian Turtschi"></author>
/// <design></design>
///
/// <history date="09/01/2002" dev="Adrian Turtschi">
/// <delta desc="created Web service"></delta>
/// </history>
/// </remarks>
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
~~~~~~~~~~~~~~
namespace wsdlModify1 {
[WebServiceAttribute(Namespace="urn:myNS")]
public class service1 : System.Web.Services.WebService {

public service1() {
InitializeComponent();
}

#region Component Designer generated code
private IContainer components = null;
private void InitializeComponent() {
}
protected override void Dispose( bool disposing ) {
if(disposing && components != null) {
components.Dispose();
}
base.Dispose(disposing);
}
#endregion

[WebMethod,changeMinOccurs("myArg1", 1), changeMinOccurs("myArg2", 1)]
public string testMethod(string myArg1, string myArg2, string myArg3) {
return myArg1 + myArg2 + myArg3;
}
}

[AttributeUsage(AttributeTargets.Method,AllowMultiple=true)]
public class changeMinOccursAttribute : Attribute {

public changeMinOccursAttribute(string parameter, int minOccurs) {
this.parameter = parameter;
this.minOccurs = minOccurs;
}

public string parameter;
public int minOccurs;
}

public class customSoapExtensionReflector : SoapExtensionReflector {
public override void ReflectMethod() {
// get method attributes
changeMinOccursAttribute[] customAttributes =
(changeMinOccursAttribute[])
this.ReflectionContext.Method.GetCustomAttributes(
typeof(changeMinOccursAttribute));
if (customAttributes != null) {
string defaultNamespace = this.ReflectionContext.DefaultNamespace;
// get the schema in the WSDL <types> section
XmlSchema xmlSchema =
this.ReflectionContext.ServiceDescription.Types.Schemas
[defaultNamespace];
// instead of working directly with the XmlSchema object we load
// the corresponding XML representation of the XSD into an
// XmlDocument and work on that level
MemoryStream memoryStream1 = new MemoryStream();
XmlWriter xmlWriter1 = new XmlTextWriter(memoryStream1,
Encoding.UTF8);
xmlSchema.Write(xmlWriter1);

XmlDocument xmlDocument = new XmlDocument();
memoryStream1.Position = 0;
xmlDocument.Load(memoryStream1);

// now we have an XmlDocument representation of the XSD. Find the
// corresponding elements of those in-parameters for which we want
to
// change the minOccurs attribute
string xmlSchemaNamespace = "http://www.w3.org/2001/XMLSchema";
XmlNamespaceManager xmlNamespaceManager =
new XmlNamespaceManager(xmlDocument.NameTable);
xmlNamespaceManager.AddNamespace("s", xmlSchemaNamespace);

// loop over all in-parameters of the Web method for which we want
to
// change the minOccurs attribute
for(int i = 0; i < customAttributes.Length; i++) {
string parameter = customAttributes[i].parameter;
int minOccurs = customAttributes[i].minOccurs;
string xPath = "//s:element[@name='" + parameter + "']";
// get the XSL element
XmlNodeList myNodeList = xmlDocument.DocumentElement.SelectNodes
(xPath, xmlNamespaceManager);
// sanity checks
if((myNodeList.Count == 1) &&
(myNodeList[0].Attributes["minOccurs"] != null)) {
// finally: change minOccurs!
myNodeList[0].Attributes["minOccurs"].Value =
minOccurs.ToString();
}
}

// write the changes back to the WSDL <types> section
MemoryStream memoryStream2 = new MemoryStream();
XmlWriter xmlWriter2 = new XmlTextWriter(memoryStream2,
Encoding.UTF8);
xmlDocument.Save(xmlWriter2);
memoryStream2.Position = 0;
xmlSchema = XmlSchema.Read(memoryStream2, null);

// remove the original version of the WSDL <types> section
this.ReflectionContext.ServiceDescription.Types.Schemas.Clear();
// replace with our new version

this.ReflectionContext.ServiceDescription.Types.Schemas.Add(xmlSchema);
}
}
}
}

Cheers,
--adrian.

Adrian Turtschi
Avanade Deutschland GmbH
http://www.avanade.com/de


"Armando Garcia" <arma...@hotmail.com> wrote in message
news:60c501c24e05$b6183d00$9de62ecf@tkmsftngxs01...

Reply all
Reply to author
Forward
0 new messages