使用命名空间前缀调用SOAP方法

3

我的C# web服务客户端向基于Java的web服务发送以下soap消息:

<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope"
               xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
               xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<soap:Body>
<getData>
<request>
<requestParameters xmlns="http://b...">
<equals>
...
</equals>
</requestParameters>
</request>
</getData>
</soap:Body>
</soap:Envelope> 

Java-based Web服务返回错误:

500 Internal Server Error
...
Cannot find dispatch method for {}getData
...

这是一个用Java编写的客户端,它能够工作并发送以下消息:

<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope"
               xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
               xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<soap:Body>
<ns2:getData xmlns:ns2="http://a...">
<ns2:request>
<ns3:requestParameters xmlns:ns3="http://b...">
<ns3:equals>
...
</ns3:equals>
</ns3:requestParameters>
</ns2:request>
</ns2:getData>
</soap:Body>
</soap:Envelope> 

在C#中有没有一种简单的方法,可以像Java客户端一样发送带有命名空间前缀的SOAP消息?

以下是发送消息的C#代码:

// class MyService is auto-generated using wsdl.exe tool
MyService service = new MyService();

RequestMessage request = new RequestMessage();
...

ResponseMessage response = service.getData(request);
...

更新:

这是RequestMessage类:

/// <remarks/>
[System.CodeDom.Compiler.GeneratedCodeAttribute("svcutil", "3.0.4506.2152")]
[System.SerializableAttribute()]
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
[System.Xml.Serialization.XmlTypeAttribute(Namespace="http://uri.etsi.org/02657/v1.5.1#/RetainedData")]
public partial class RequestMessage
{

    private byte[] requestPriorityField;

    private RequestConstraints requestParametersField;

    private string deliveryPointHIBField;

    private string maxHitsField;

    private NationalRequestParameters nationalRequestParametersField;

    private System.Xml.XmlElement anyField;

    /// <remarks/>
    [System.Xml.Serialization.XmlElementAttribute(DataType="hexBinary", Order=0)]
    public byte[] requestPriority
    {
        get
        {
            return this.requestPriorityField;
        }
        set
        {
            this.requestPriorityField = value;
        }
    }

    /// <remarks/>
    [System.Xml.Serialization.XmlElementAttribute(Order=1)]
    public RequestConstraints requestParameters
    {
        get
        {
            return this.requestParametersField;
        }
        set
        {
            this.requestParametersField = value;
        }
    }

    /// <remarks/>
    [System.Xml.Serialization.XmlElementAttribute(Order=2)]
    public string deliveryPointHIB
    {
        get
        {
            return this.deliveryPointHIBField;
        }
        set
        {
            this.deliveryPointHIBField = value;
        }
    }

    /// <remarks/>
    [System.Xml.Serialization.XmlElementAttribute(DataType="integer", Order=3)]
    public string maxHits
    {
        get
        {
            return this.maxHitsField;
        }
        set
        {
            this.maxHitsField = value;
        }
    }

    /// <remarks/>
    [System.Xml.Serialization.XmlElementAttribute(Order=4)]
    public NationalRequestParameters nationalRequestParameters
    {
        get
        {
            return this.nationalRequestParametersField;
        }
        set
        {
            this.nationalRequestParametersField = value;
        }
    }

    /// <remarks/>
    [System.Xml.Serialization.XmlAnyElementAttribute(Order=5)]
    public System.Xml.XmlElement Any
    {
        get
        {
            return this.anyField;
        }
        set
        {
            this.anyField = value;
        }
    }
}

更新 #2:

Java基于的网络服务不喜欢我用C#客户端生成的SOAP消息,并不是因为缺少命名空间前缀,而仅仅是因为getData元素中缺少xmlns。如果我的消息看起来像这样:

...
<getData xmlns="http://a...">
...
</getData>
...

它起作用了!

我成功地将xmlns放入getData中,通过手动编辑wsdl.exe生成的源代码中的SoapRpcMethodAttribute。这是摘录:

/// <remarks/>
[System.CodeDom.Compiler.GeneratedCodeAttribute("wsdl", "2.0.50727.3038")]
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
[System.Web.Services.WebServiceBindingAttribute(
    Name="AxxxPortTypeBinding", Namespace="http://a...")]
public partial class AxxxService 
    : System.Web.Services.Protocols.SoapHttpClientProtocol {

    ...

    /// <remarks/>
    [System.Web.Services.Protocols.SoapRpcMethodAttribute(
        "http://a.../getData", 
        RequestNamespace = "http://a...", 
        ResponseNamespace = "http://a...",
        Use = System.Web.Services.Description.SoapBindingUse.Literal)]
    [return: System.Xml.Serialization.XmlElementAttribute("response")]
    public ResponseMessage getData(RequestMessage request) {
        object[] results = this.Invoke("getData", new object[] {
                    request});
        return ((ResponseMessage)(results[0]));
    }

    ...
}

在我的更改之前,SoapRpcMethodAttribute具有以下构造函数:
[System.Web.Services.Protocols.SoapRpcMethodAttribute(
    "", RequestNamespace = "", ResponseNamespace = "",
    Use = System.Web.Services.Description.SoapBindingUse.Literal)]

现在的问题是:在WSDL文件中放置什么内容,使得SoapRpcMethodAttribute在构造函数中拥有那些字符串(由wsdl.exe工具填充)?


你是否使用wsdl.exe生成了你的服务代理? - Wes P
请提供更多的上下文信息,以便我能够准确地翻译该程序相关内容。 - mvladic
3个回答

1

我以前见过这个问题,WSDL.exe工具在生成服务代码时没有正确地引入命名空间。检查生成的代码中request对象定义。我猜测,request对象的类定义中没有定义XmlRootAttribute属性。

request对象的类定义中添加属性[XmlRootAttribute(Namespace "http://a...")]应该可以解决这个问题。

另外,我建议在一个单独的代码文件中使用部分类定义来添加这个附加属性。在单独的文件中定义属性将允许您在需要时使用WSDL.exe重新生成Web服务代码,而不会覆盖设置根元素命名空间的修复。


是的,你说得对,在RequestMessage类定义中(或同一自动生成文件中的任何其他类中)没有XmlRootAttribute。 - mvladic
我已经在类定义中添加了XmlRootAttribute,但没有起作用。 - mvladic
@mvladic,您上面发布的示例显示您添加了XmlTypeAttribute属性,而不是XmlRootAttribute属性。鉴于您的示例SOAP请求,应将RequestMessage类标识为发送的XML消息的根元素。我还注意到从您的示例中,服务返回一个响应(可能在ResponseMessage类中?)。您还需要使用XmlRootAttribute属性装饰此响应类,以确保使用正确的命名空间返回响应。 - pmartin
我发布的示例是原始的,由wsdl工具生成。正如你建议的那样,我尝试添加XmlRootAttribute,但没有帮助。 - mvladic

0

生成的代理类应该有正确的命名空间。我建议两件事:

1)从命令行运行WSDL.EXE并注意是否有任何错误或警告。如果有,请编辑您的问题以包括它们。

2)除非您被困在使用.NET 2.0上,否则您应该尝试使用“添加服务引用”或等效的“SVCUTIL.EXE”创建您的代理类,这些将在客户端使用现代的WCF基础结构,这更有可能已经被修复以解决此问题。


“Add Service Reference” 仅适用于 asmx,而我只有一个 WSDL 和一个 XSD 文件。 - mvladic
我使用“svcutil my.wsdl my.xsd /language:C#”创建了客户端,但仍然无法正常工作 - 没有命名空间前缀。 - mvladic
我在我的问题中添加了RequestMessage类的定义。 - mvladic
@mvladic:你应该向微软报告这个问题,网址是http://connect.microsoft.com/visualstudio/。一定要包括WSDL和任何包含的XSD文件。与ASMX不同,WCF正在积极开发中,错误应该会得到修复。 - John Saunders
1
@mvladic:您对“添加服务引用”一词的理解是错误的——它也适用于 WSDL。它只查找 .asmx 或 .svc 的原因是为了找到 WSDL。 - John Saunders

-1
我曾经遇到过同样的问题,并通过更改每个 Web 服务方法对应的 System.Web.Services.Protocols.SoapDocumentMethodAttribute 属性中的 Use 值来解决它。 将 System.Web.Services.Description.SoapBindingUse.Literal 默认值替换为 System.Web.Services.Description.SoapBindingUse.Encoded

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接