手动编写WCF POX帖子

时间:2009-07-02 19:16:27

标签: xml web-services wcf

假设我有一个WCF合同,例如

[ServiceContract]
public interface IContract
{
    [OperationContract]
    [WebInvoke(Method="POST", RequestFormat=WebMessageFormat.Xml, BodyStyle=WebMessageBodyStyle.Wrapped)]
    string ComplexPost(string name, ComplexType data);
}

和数据合同:

[DataContract(Name="ComplexType", Namespace="")] // don't know if those atts are req'd or not but saw them in another example
public class ComplexType
{
    public string StringData { get; set; }
    public int IntData { get; set; }
    public DateTime DateValue { get; set; }
}

我知道请求必须被包装才能拥有多个输入参数,显然你不能拥有一个带有多个root的XML文档。

问题是,文档实际上很少包含你必须包装它的内容。

目标不是通过WCF使用它,客户端需要作为通用XML Web服务访问它。他们可能不了解WCF甚至不使用.NET。

显然,我可以从我收到的例外中看出,它期望一个名为ComplexPost的元素(与方法名称相同),名称空间为http://tempuri.org/,因为我还没有指定任何其他内容,所以我知道我需要这个:

<ComplexPost xmlns="http://tempuri.org/">

...what exactly?

</ComplexPost>

目标不是专门遵守REST原则。我不是在寻找在UriTemplate中嵌入一些参数的答案,只留下一个复杂的对象,使Bare工作。我正在寻找一个通用的解决方案来包含POST体内的所有数据。

找到Fiddler

根据我使用Fiddler所发现的结果,这里大致是结果。

<ComplexPost xmlns="http://tempuri.org/">
    <name>Value of name parameter</name>
    <data xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
        <StringData>The StringData property value</StringData>
        <IntData>10</IntData>
        <DateValue>2009-07-07T15:38:39.7738012-05:00</DateValue>
    </data>
<ComplexPost>

因此,wrapper元素是方法名称,具有在ServiceContract上指定的XML名称空间,如果没有,则为temppuri.org。

每个参数按顺序变为子元素,基本类型很容易序列化为字符串表示。

我使用可空值进行了测试,包括可以为空的DateTime。显然xmlns:i =“http://www.w3.org/2001/XMLSchema-instance”的声明必须在它需要之前发生,然后对于null值,它是一个闭合的元素,其中i:nil =“true” ,例如

<NullableDateProperty i:nil="true" />

DataContract对象也很容易拥有子复杂类型,甚至是复杂对象列表。

....
<ChildObjectPropertyName>
    <PropertyOfChildObject>value</PropertyOfChildObject>
    ...
</ChildObjectPropertyName>
<ListProperty>
    <ObjectType>
        <ObjectProperty>value</ObjectProperty>
        ....
    </ObjectType>
    ...
</ListProperty>

这可能不完整,但教训肯定是让WCF客户端工作,然后检查与Fiddler的交流。谢谢Cheeso!

2 个答案:

答案 0 :(得分:1)

如果我这样做,发布一个基于WCF的REST / POX服务,我想通过“任何人和任何东西”使它可以使用我将使用调试HTTP代理,如Fiddler2,并捕获一个成功请求从WCF REST客户端到WCF REST服务器。

这可以作为文档和示例开头的基础,也可以是一组脚本测试。

还有一种方法可以在WCF中打开消息跟踪,但我不知道。我一直用Fiddler。事实上,我现在就打开

答案 1 :(得分:1)

我不太明白你的目标......

“普通”WCF服务是一种SOAP服务 - 它本身可与任何说SOAP的其他任何东西互操作 - 例如Java,PHP - 你的名字。难道你不能只是创建你的WCF服务和随附的DataContract成为一个成熟的SOAP服务并与你的客户互操作吗?

如果不是 - 如果使用REST,基本上会发生什么,那就是DataContractSerializer会将您的DataContract(服务的数据表示)序列化为XML。您可以使用以下代码段轻松地在代码中手动测试:

DataContractSerializer dcs = new DataContractSerializer(typeof(YourDataContract));

FileStream outputFile = new FileStream(@"C:\output.xml");
dcs.WriteObject(outputFile, yourTestDataInstance);

“yourTestDataInstance”(类型为“YourDataContract”)的序列化输出将写入C:\ output.xml并准备好进行检查。

当然,当您浏览服务URL时,您可以看到REST结果。所以你可能需要稍微调整一下结果 - 但是你应该很容易实现你感兴趣的东西。

DataContract上的“Name =”属性允许您为XML中的根元素指定不同的名称 - 例如如果您想要“Root”而不是“YourDataContract”,请使用“Name = Root”属性。

Namespace =属性旨在允许您将数据协定放入您自己的单独XML命名空间中 - 就像.NET命名空间一样,它允许您消除数据歧义,使其完全独特,并确保您自己的“客户”不会与来自其他地方的另一个名为“客户”的XML元素发生冲突。

这两个属性都是可选的 - 如果您不想这样做,则无需指定它们。

马克