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 {
Steven
source share