在反序列化WCF服务时更改文化

时间:2009-09-22 13:19:18

标签: c# wcf cultureinfo

我正在使用C#从Java-webservice读取数据。

我在VS2008中为服务器创建了一个服务引用,并且可以调用那里的一个方法。但是,返回的一些字段是Decimal类型,并且当自动生成的WCF代理获取XML时,它失败并显示CommunicationException:

"Error in deserializing body of reply message for operation 'getOpenReceivables'."
"There is an error in XML document (1, 941)."
"Input string was not in a correct format."

[编辑]这是一个完整的堆栈跟踪:

at System.Number.StringToNumber(String str, NumberStyles options, NumberBuffer& number, NumberFormatInfo info, Boolean parseDecimal)
at System.Number.ParseDecimal(String value, NumberStyles options, NumberFormatInfo numfmt)   
at System.Decimal.Parse(String s, NumberStyles style, IFormatProvider provider)
at System.Xml.XmlConvert.ToDecimal(String s)
at Microsoft.Xml.Serialization.GeneratedAssembly.XmlSerializationReaderExecutePortType.Read2_XXNG_OPEN_RECEIVABLES(Boolean isNullable, Boolean checkType)
at Microsoft.Xml.Serialization.GeneratedAssembly.XmlSerializationReaderExecutePortType.Read3_Item()  
at Microsoft.Xml.Serialization.GeneratedAssembly.ArrayOfObjectSerializer.Deserialize(XmlSerializationReader reader)
at System.Xml.Serialization.XmlSerializer.Deserialize(XmlReader xmlReader, String encodingStyle, XmlDeserializationEvents events)

我可以看到返回的十进制数用十进制数作为十进制格式。出于测试目的,我尝试了Decimal.Parse(“123.99”)并得到了同样的错误。通过设置

System.Threading.Thread.CurrentThread.CurrentCulture = new CultureInfo("en-US");

在我的Decimal.Parse(“123.99”)的测试代码之前,我得到了它。

但是,在调用WCFService方法之前设置CurrentCulture没有任何区别。

有什么方法可以让我的WCFService代理对象理解返回的XML是否在另一种文化格式中?

4 个答案:

答案 0 :(得分:2)

您是否尝试过使用自定义IClientMessageFormatter.DeserializeReply()实施? WCF通过扩展点填充到gill中,因此通常很难知道要选择哪一个,但DeserializeReply看起来像是这项工作的正确工具。

查看this blog post-- sorry its original site is offline so pointing to Internet Archive version,它看起来与您尝试做的类似:使用WCF客户端调用非WCF Web服务,并对帐户响应进行专门处理用于服务器上的非WCF行为。

以下是该博客的代码摘录:

public object DeserializeReply(Message message, object[] parameters)
{
    object helperInstance = Activator.CreateInstance(_return);

    //we have special condition where service sets Http response code to 403 that signals that an error has occured 
    KeyValuePair<string,object> serviceErrorProperty = message.Properties.FirstOrDefault(p => p.Key == ResponseErrorKey);
    if (serviceErrorProperty.Key != null)
    {
        //we have an error message
        IResponseErrorProvider responseErrorProvider = helperInstance as IResponseErrorProvider;
        if (responseErrorProvider != null)
        {
            //unpack the error payload from message and assign to the object
            ResponseError payload = message.GetBody<ResponseError>();
            responseErrorProvider.ServiceError = payload;

            //return fixed null type with error attached to it
            return helperInstance;
        }
    }

    //another message we might get is <nil-classes type="array"/> for empty arrays.
    XmlDictionaryReader xdr = message.GetReaderAtBodyContents();
    xdr.MoveToContent();

    if (xdr.Name == NullMessage)
    {
        return helperInstance; //standin for the null value
    }

    return _formatter.DeserializeReply(message, parameters);
}

public Message SerializeRequest(MessageVersion messageVersion, object[] parameters)
{
    return _formatter.SerializeRequest(messageVersion, parameters);
}

答案 1 :(得分:1)

您可以将文化初始值设定项附加到您随后添加到端点的行为。这将在线程上设置文化反序列化响应,因此该字段应该正确反序列化。

有关此代码的示例,请查看此链接:

http://blogs.msdn.com/drnick/archive/2008/02/26/using-call-context-initializers-for-culture.aspx

答案 2 :(得分:0)

如果文化确实是问题,我会感到非常惊讶。 XML规范说小数点使用点作为分隔符,(de)序列化器知道这一点。你能跟踪消息并看看941位置的内容吗? (顺便说一句:除了WCF跟踪,我喜欢SoapUI这样的事情)当涉及到小数时,可能不同的精度可能是一个问题:也许Java服务在结尾7之前放置更多666666666666 .net十进制可以处理的三分之一?

答案 3 :(得分:0)

还有第二种选择:小数不是真正的小数(再次:跟踪消息会非常有启发性)。我发现this link对亚马逊服务有点遗憾,可能会将单位置于十进制值(顺便说一句:WTF!?)。但是,在使用IClientMessageInspector接口将原始消息传递给反序列化之前,有一个很好的描述如何与原始消息进行交互。如果这样一个奇怪的案例是你的问题,你可以强迫服务提供商遵守他自己的合同或做这样的伎俩(如果提供商超出你的控制范围,并说“这是设计的”)。