WCF WSDL + Nillable属性

时间:2012-01-27 20:48:33

标签: c# wcf wsdl

我有一个Flattened WSDL的WCF服务,另一端的消费者告诉我nillable =“true”属性正在填充它们。我尝试在服务合同中设置EmitDefaultValue = false,但我没有注意到行为的任何变化。

不可否认,我从来没有在这个级别深入研究WSDL生成,所以我有点迷失。也许在下面发布的代码中有一些调整可以解决我的问题?如果我至少在正确的位置,我会继续调查。

是否有一种简单的方法可以从我的WSDL中删除nillable =“true”属性,这会产生意想不到的后果吗?谢谢!

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...
}

2 个答案:

答案 0 :(得分:1)

没有直接的简单方法来实现这一目标。您必须自己使用WsdlExporter来实现它。是否会产生意想不到的后果取决于您的意图: - )

编辑:

查看IWSDLExportExtension的MSDN示例。它将允许您完全按照自己的意愿行事。不可否认,要做到这一点有点麻烦,但你正朝着正确的方向前进。

答案 1 :(得分:1)

在网上搜索了我们之后,我和我的团队决定采用不同的方法来摆脱nillable =“true”。我们做了以下几点:

  1. 在应用程序启动期间注册了特殊HttpModule
  2. 此模块为BeginRequest事件注册了一个处理程序。
  3. 如果请求WSDL或XSD(通过查看查询字符串进行检查),钩子处理程序将用装饰器(Stream)替换默认的Response.Filter
  4. 此装饰器将缓冲写入的数据,直到文档结束。
  5. 当所有数据都被写入时,装饰器会根据该数据构建一个XDocument并通过该文档进行设置(除其他外,例如添加文档)nillable =“false”。
  6. 这非常可爱。

    找到使用Response.Filter的想法here

    这是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) { ... }
    }
    

    这是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是所有魔法发生的地方:

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