WCF WSDL + Nillable Attributes

前端 未结 2 1435
后悔当初
后悔当初 2021-01-23 17:52

I have a WCF service with a Flattened WSDL, and the consumer at the other end is telling me the nillable=\"true\" attributes are hosing them up. I tried setting EmitDefaultValue

2条回答
  •  被撕碎了的回忆
    2021-01-23 18:47

    After searching the internet for ours, me and my team decided to go with a different approach to get rid of the nillable="true". What we did was the following:

    1. Registered a special HttpModule during application startup.
    2. This module registered a handler to the BeginRequest event.
    3. In the case the WSDL or XSD are requested (checked by looking at the query string) the hooked handler would replace the default Response.Filter with a decorator (a Stream).
    4. This decorator would buffer the written data until the end of the document was reached.
    5. When all data is written the decorator builds up an XDocument based on that data and goes through that document to set (among other things, such as adding documentation) nillable="false".

    This works all quite lovely.

    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 = "";
        private const string SchemaEndOfFileMarker = "";
    
        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(" -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;
                    }
                }
            }
        }
    }
    

    The WsdlAnnotator is where all the magic happens:

    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);
        }
    

提交回复
热议问题