我想定义一个C#WCF服务,该服务公开由给定格式的消息调用的操作。下面给出了该消息的一个例子。该格式由我无法控制的客户定义。我只控制服务端。
总之,我有一个WCF操作,它应该将数组作为唯一参数。数组参数以下面的示例消息显示的方式表示。但是,该参数当前未正确反序列化,并且在服务端最终为空,尽管它似乎正确地表示在来自客户端的SOAP消息中。如何更改我的WCF服务以使参数正确反序列化?
(我知道有很多问题似乎非常相似和冗长的MSDN文章关于如何反序列化各种格式的集合和数组,但由于某种原因我一直遇到问题或者我根本无法采取一个类似的问题的答案,并将其应用于我的场景)。
以下是我已尝试过的许多内容:
OperationFormatStyle
上的OperationFormatUse
和OperationContract
属性。ServiceKnownType
string[]
属性而不是ItemNameAttribute
属性
OperationFormatStyle.Rpc
)中数组元素的名称。我认为我已经接近了与原始代码相比有用的东西。在使用OperationFormatUse.Encoded
和FaultException
之前,我只收到<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:tns="urn:iControl" xmlns:types="urn:iControl/encodedTypes" xmlns:xsi="http://www.w3.org/2001/XMLSchema-
instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<s:Header xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
<To s:mustUnderstand="1" xmlns="http://schemas.microsoft.com/ws/2005/05/addressing/none">https://127.0.0.1/iControl/iControlPortal.cgi</To>
<Action s:mustUnderstand="1" xmlns="http://schemas.microsoft.com/ws/2005/05/addressing/none">urn:iControl:GlobalLB/DataCenter</Action>
</s:Header>
<soap:Body soap:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
<q1:get_object_status xmlns:q1="urn:iControl:GlobalLB/DataCenter">
<data_centers href="#id1" />
</q1:get_object_status>
<soapenc:Array id="id1" soapenc:arrayType="xsd:string[3]">
<Item>Datacenter 5d4afe7f-f4e0-4660-9ff1-9c1f8a15a1df</Item>
<Item>Datacenter 70d88638-4622-46f1-8978-773898f57b0f</Item>
<Item>Datacenter c8fc4b53-af74-4f71-b7a7-9102fbd684b6</Item>
</soapenc:Array>
</soap:Body>
</soap:Envelope>
,说明请求无法反序列化。
使用下面的代码,至少我没有任何异常,但服务端的反序列化数组是空的。
以下是我收到的消息示例,该消息应该使用单个字符串数组类型参数调用操作:
[GeneratedCode("System.ServiceModel", "4.0.0.0")]
[ServiceContract(Name = "IGlobalLB.DataCenterPortType", Namespace = "urn:iControl", ConfigurationName = "IGlobalLBDataCenterPortType"), DispatchByBodyElementBehavior]
public interface IGlobalLBDataCenterPortType
{
// ...
[OperationContract(Action = "urn:iControl:GlobalLB/DataCenter", ReplyAction = "ra")]
[XmlSerializerFormat(Style = OperationFormatStyle.Document, SupportFaults = true, Use = OperationFormatUse.Literal)]
[ServiceKnownType(typeof(string[]))]
get_object_statusResponse get_object_status(get_object_statusRequest request);
// ...
}
这是我最终达成的运营合同。原始的一个是用“svcutil”生成的,我相信,但我不再使用当时使用的原始WSDL文件。不过,我完全可以控制这个部分,所以我可以调整服务端的代码以适应任何工作。有一个自定义操作选择器在执行调度,但一切似乎都在工作,因为调用服务端的实现方法,当我只是用字符串替换字符串数组(同时保留其他所有内容)时,参数结束正确的方法。
data_centers
这是请求数据合同的样子。如上所述,传递原始参数(如普通字符串)而不是字符串数组(即将string[]
的类型从string
更改为[DebuggerStepThrough()]
[GeneratedCode("System.ServiceModel", "4.0.0.0")]
[EditorBrowsable(EditorBrowsableState.Advanced)]
[MessageContract(WrapperName = "get_object_status", WrapperNamespace = "urn:iControl:GlobalLB/DataCenter",
IsWrapped = true)]
[KnownType(typeof(string[]))]
public partial class get_object_statusRequest
{
[MessageBodyMember(Namespace = "", Order = 0)]
public string[] data_centers;
public get_object_statusRequest()
{
}
public get_object_statusRequest(string[] data_centers)
{
Console.WriteLine("XXX: " + String.Join(" ", data_centers));
this.data_centers = data_centers;
}
}
),按预期工作。
public get_object_statusResponse get_object_status(get_object_statusRequest request)
{
Console.WriteLine("Arguments: " + request.data_centers);
Console.WriteLine("Datacenters:");
foreach (var d in request.data_centers)
{
Console.WriteLine(d);
}
return new get_object_statusResponse();
}
以下是操作实现:
Arguments: System.String[]
Datacenters:
输出如下,即没有数组元素进入方法。我原本希望示例消息中的字符串包含在传递的数组中。
REM Usage: SLEEP Time_in_MiliSECONDS
@ECHO off
ping 1.0.0.0 -n 1 -w %1 > nul