我们观察到,当我们公开一个使用各种xml序列化属性修饰的类的WCF服务时,尽管我们在接口上使用了XmlSerializerFormat属性,但任何操作参数的XmlRoot属性都会被完全忽略。 参数的名称空间始终是服务的名称空间,而不是我们指定的名称空间。
这引起了我们的问题,因为它似乎没有与ASMX向后兼容,也因为我们正在使用BizTalk,并且需要更严格地控制XML交换的形状。
然后有几个问题 -
我看过this帖子,但我不相信这与我的问题有关 -
根据Wagner Silveira的要求 - 我用来测试的合同是 -
[ServiceContract(Namespace = "http://servicecontract"),
XmlSerializerFormat(Style = OperationFormatStyle.Document)]
public interface ITestService
{
[OperationContract]
MyOtherType MyTestMethod(MyType obj);
}
// Composite class for DCS and XMLS
[Serializable, XmlType, XmlRoot(Namespace = "http://datacontract")]
public class MyType
{
[XmlAttribute]
public string StringValue { get; set; }
}
// Composite class for DCS and XMLS
[Serializable, XmlType, XmlRoot(Namespace = "http://datacontract")]
public class MyOtherType
{
[XmlAttribute]
public string OtherStringValue { get; set; }
}
答案 0 :(得分:3)
我假设你使用SOAP作为消息格式。在这种情况下,您要序列化的对象不是XML的根,肥皂信封是。因此,忽略XmlRoot是有道理的。默认情况下,WCF将为您创建一个消息合同并命名响应,并且它具有服务的命名空间。您可以做create your own message contract来完全控制SOAP。
创建以下两个类:
[MessageContract]
public class MyTestMethodRequest
{
[MessageBodyMember( Namespace = "http://datacontract" )]
public MyType MyType;
}
[MessageContract]
public class MyTestMethodResponse
{
[MessageBodyMember( Namespace = "http://datacontract" )]
public MyOtherType MyOtherType;
}
然后将服务操作的签名更改为以下内容。
[OperationContract]
public MyTestMethodResponse MyTestMethod( MyTestMethodRequest request )
{
return new MyTestMethodResponse {
MyOtherType = new MyOtherType {
OtherStringValue = "bar"
}
};
}
现在,如果您举例说明SOAP消息,您应该看到以下内容:
请求强>
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
<s:Header>
<Action xmlns="http://schemas.microsoft.com/ws/2005/05/addressing/none"
s:mustUnderstand="1">http://servicecontract/TestService/MyTestMethod</Action>
</s:Header>
<s:Body xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<MyTestMethodRequest xmlns="http://servicecontract">
<MyType StringValue="foo" xmlns="http://datacontract" />
</MyTestMethodRequest>
</s:Body>
</s:Envelope>
<强>响应强>
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
<s:Header />
<s:Body xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<MyTestMethodResponse xmlns="http://servicecontract">
<MyOtherType OtherStringValue="bar" xmlns="http://datacontract" />
</MyTestMethodResponse>
</s:Body>
</s:Envelope>
答案 1 :(得分:1)
我不知道为什么WCF会忽略XmlRoot,所以我无法回答你问题的那一部分。但我确实有几种方法可以解决这个问题。
首先使用WSDL。
如果您希望将一组特定的XML命名空间应用于已发送和接收的消息,请使用WSDL和XML Schema明确指定它们。
然后,通过the svcutil.exe tool直接从该WSDL生成服务器端存根代码或客户端代理代码。
<强> use a custom ServiceHost 强>
在this link中描述的另一个选项是使用自定义ServiceHost来覆盖WCF决定忽略消息类型的XmlRoot或XmlType属性。
如果您选择使用WSDL-First方法,则WSDL应如下所示:
<?xml version="1.0" encoding="utf-8" ?>
<definitions
xmlns="http://schemas.xmlsoap.org/wsdl/"
targetNamespace="urn:The-Service-namespace"
xmlns:tns="urn:The-Service-namespace"
xmlns:s="http://www.w3.org/2001/XMLSchema"
xmlns:n0="urn:The-Request-namespace"
xmlns:n1="urn:The-Response-namespace"
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
elementFormDefault= "unqualified"
>
<types>
<s:schema targetNamespace="urn:The-Request-namespace" >
<s:complexType name="Type1">
<s:sequence>
<s:element name="x" minOccurs="1" maxOccurs="1" type="s:string"/>
</s:sequence>
</s:complexType>
<s:element name="Type1" type="n0:Type1" />
</s:schema>
<s:schema targetNamespace="urn:The-Response-namespace" >
<s:complexType name="Type2">
<s:sequence>
<s:element name="x" minOccurs="1" maxOccurs="1" nillable="false" type="s:string"/>
<s:element name="y" minOccurs="1" maxOccurs="1" nillable="false" type="s:int"/>
<s:element name="z" minOccurs="1" maxOccurs="1" nillable="false" type="s:boolean" />
</s:sequence>
</s:complexType>
<s:element name="Type2" type="n1:Type2" />
</s:schema>
</types>
<message name="RequestMessage">
<part name="inPart1" element="n0:Type1" />
</message>
<message name="ResponseMessage">
<part name="outPart1" element="n1:Type2" />
</message>
<portType name="PortTypeName">
<operation name="Method1">
<input message="tns:RequestMessage" />
<output message="tns:ResponseMessage" />
</operation>
</portType>
<binding name="InterfaceName" type="tns:PortTypeName">
<soap:binding
transport="http://schemas.xmlsoap.org/soap/http"
style="rpc" />
<operation name="Method1">
<soap:operation soapAction="" style="document" />
<input> <soap:body use="literal" /> </input>
<output> <soap:body use="literal" /> </output>
</operation>
</binding>
</definitions>
这个WSDL非常简单 - 它定义了一个操作,只有一个请求消息和一个响应消息。
请注意,有三个xml命名空间:
如果您的Web服务接口更复杂,有更多操作,因此有更多请求和响应消息类型,您可以为所有这些其他类型添加更多名称空间(如果您愿意)。