WCF WSDL + Nillable Attributes

I have a WCF service with Flattened WSDL and the consumer on the other end tells me that the nillable = "true" attributes are pushing them. I tried to set EmitDefaultValue = false in my service contract, but I did not notice any changes in behavior.

Admittedly, I never had to delve into the WSDL generation at this level before I get a little lost. Maybe there is a fine-tuning to a bit of code that you find below that can solve my problem? If I'm at least in the right place, I will continue the investigation.

Is there an easy way to remove the nillable = "true" attributes from my WSDL and this will have unintended consequences? Thanks!

public class FlatWsdl : IWsdlExportExtension, IEndpointBehavior { public void ExportEndpoint(WsdlExporter exporter, WsdlEndpointConversionContext context) { XmlSchemaSet schemaSet = exporter.GeneratedXmlSchemas; foreach (ServiceDescription wsdl in exporter.GeneratedWsdlDocuments) { List<XmlSchema> importsList = new List<XmlSchema>(); foreach (XmlSchema schema in wsdl.Types.Schemas) { AddImportedSchemas(schema, schemaSet, importsList); } wsdl.Types.Schemas.Clear(); foreach (XmlSchema schema in importsList) { RemoveXsdImports(schema); wsdl.Types.Schemas.Add(schema); } } } ...omitted the rest of FlatWsdl.cs for brevity... } 
+1
c # wsdl wcf
source share
2 answers

There is no direct simple way to achieve this. You will need to use WsdlExporter to implement it yourself. Whether this will have unintended consequences depends on your intentions :-)

EDIT:

See the MSDN IWSDLExportExtension example. This will allow you to do exactly what you want. Admittedly, it's a bit of a hassle to fix it, but you're looking in the right direction.

+1
source share

After searching the Internet for ours, my team and I decided to go with a different approach to get rid of nillable = "true". We have done the following:

  • When the application starts, a special HttpModule registered.
  • This module has registered a BeginRequest event handler.
  • In the case of a WSDL or XSD request (checked by searching for the query string), the hooked handler will replace Response.Filter with a decorator (stream) by default.
  • This decorator will buffer the recorded data until the end of the document is reached.
  • When all the data is written, the decorator creates an XDocument based on this data and passes through this document to install (among other things, for example, adding documentation) nillable = "false".

It works very nice.

The idea of โ€‹โ€‹using Response.Filter was found here .

Here's the HttpModule:

 public class WsdlInterceptionHttpModule : IHttpModule { public void Init(HttpApplication application) { application.BeginRequest += (sender, e) => { var context = application.Context; if (IsRequestForWsdl(context.Request)) { context.Response.Filter = new WsdlAnnotationsFilterDecorator(context.Response.Filter); } }; } private static bool IsRequestForWsdl(HttpRequest request) { ... } } 

Here's the WsdlAnnotationsFilterDecorator :

 public class WsdlAnnotationsFilterDecorator : Stream { private const string DefinitionsEndOfFileMarker = "</wsdl:definitions>"; private const string SchemaEndOfFileMarker = "</xs:schema>"; private readonly Stream inputStream; private readonly StringBuilder responseXml = new StringBuilder(); private bool firstWrite = true; private string endOfFileMarker = DefinitionsEndOfFileMarker; public WsdlAnnotationsFilterDecorator(Stream inputStream) { this.inputStream = inputStream; this.responseXml = new StringBuilder(); } public override bool CanRead { get { return true; } } public override bool CanSeek { get { return true; } } public override bool CanWrite { get { return true; } } public override long Length { get { return 0; } } public override long Position { get; set; } public override void Close() { inputStream.Close(); } public override void Flush() { inputStream.Flush(); } public override long Seek(long offset, SeekOrigin origin) { return inputStream.Seek(offset, origin); } public override void SetLength(long length) { inputStream.SetLength(length); } public override int Read(byte[] buffer, int offset, int count) { return inputStream.Read(buffer, offset, count); } public override void Write(byte[] buffer, int offset, int count) { string valueToWrite = UTF8Encoding.UTF8.GetString(buffer, offset, count); SetEndOfFileMarker(valueToWrite); if (!valueToWrite.EndsWith(this.endOfFileMarker)) { responseXml.Append(valueToWrite); } else { responseXml.Append(valueToWrite); string finalXml = responseXml.ToString(); finalXml = WsdlAnnotator.Annotate(finalXml); byte[] data = UTF8Encoding.UTF8.GetBytes(finalXml); inputStream.Write(data, 0, data.Length); } } private void SetEndOfFileMarker(string valueToWrite) { if (firstWrite) { int definitionTagIndex = valueToWrite.IndexOf("<wsdl:definitions"); int schemaTagIndex = valueToWrite.IndexOf("<xs:schema"); if (definitionTagIndex > -1 || schemaTagIndex > -1) { firstWrite = false; if (definitionTagIndex > -1 && schemaTagIndex > -1) { endOfFileMarker = definitionTagIndex < schemaTagIndex ? DefinitionsEndOfFileMarker : SchemaEndOfFileMarker; } else if (definitionTagIndex > -1) { endOfFileMarker = DefinitionsEndOfFileMarker; } else if (schemaTagIndex > -1) { endOfFileMarker = SchemaEndOfFileMarker; } } } } } 

WsdlAnnotator all the magic happens here:

 internal static class WsdlAnnotator { internal static string Annotate(string xml) { XDocument document = XDocument.Parse(xml); try { // Your magic here. } catch (Exception ex) { throw new InvalidOperationException( ex.Message + " Document: " + document.ToString(), ex); } return document.ToString(SaveOptions.None); } 
+1
source share

All Articles