【问题标题】:WCF WSDL + Nillable AttributesWCF WSDL + 可空属性
【发布时间】:2012-01-27 20:48:33
【问题描述】:

我有一个带有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...
}

【问题讨论】:

标签: c# wcf wsdl


【解决方案1】:

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

编辑:

查看 IWSDLExportExtension 的 MSDN 示例。它可以让你做你想做的事。诚然,要做到正确有点麻烦,但您正在寻找正确的方向。

【讨论】:

  • 我最终选择不采取任何行动,但如果我要尝试删除可空属性,我会在 ExportEndpoint 方法中使用 WsdlExporter。
  • .Net 4.5 中的这种行为是否有一些变化?我现在将面临同样的情况。项目中没有 IWSDLExportExtension。
【解决方案2】:

在互联网上搜索了我们的方法后,我和我的团队决定采用不同的方法来摆脱 nillable="true"。我们所做的如下:

  1. 在应用程序启动期间注册了一个特殊的HttpModule
  2. 此模块向 BeginRequest 事件注册了一个处理程序。
  3. 在请求 WSDL 或 XSD 的情况下(通过查看查询字符串进行检查),挂钩处理程序会将默认的 Response.Filter 替换为装饰器(流)。
  4. 此装饰器将缓冲写入的数据,直到到达文档末尾。
  5. 写入所有数据后,装饰器会根据该数据构建一个XDocument,并通过该文档设置(除其他外,例如添加文档)nillable="false"。

这一切都很可爱。

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-10-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-02-16
    相关资源
    最近更新 更多