WSDL的object[]数组赋值Guid数组时编译及序列化失败求助
问题描述
使用VS2022「添加连接服务」引入第三方不可修改的WSDL服务,服务版本更新后要求传入数组而非单一值。其中CancelIndiciumRequest类的Items属性为object[]类型,厂商推荐赋值Guid[]而非string[],但遇到以下问题:
- 直接赋值
Guid[]出现编译错误:Cannot implicitly convert type 'System.Guid[]' to 'object[]' - 转换为
object[]后运行时触发XML序列化错误:The type System.Guid may not be used in this context
相关代码
主调用方法
internal int CancelLabel(string trackNum) { CancelIndiciumRequest req = new CancelIndiciumRequest { Item = GetCredsType(), // 以下是尝试过的赋值方式(均有问题) // Items = (object[]) new Guid[] { new Guid(trackNum) }, // 编译错误 // Items = (new List<Guid> { new Guid(trackNum) }).ToArray(), // 运行时错误 // Items = GetArrayGuid(trackNum), // 运行时错误 // Items = GetGuids(trackNum).ToArray(); // 运行时错误 }; // ... 省略其他代码 resp = GetResponse(req); }
支持方法
private List<Guid> GetGuids(string TxID) { return new List<Guid> { new Guid(TxID) }; } private object[] GetArrayGuid(string sGuid) { object[] oAry = new object[1]; oAry[0] = new Guid(sGuid); return oAry; }
调用代码
private CancelIndiciumResponse GetResponse(CancelIndiciumRequest req) { XSoap x = sFactory.CreateChannel(); CancelIndiciumResponse resp = null; int retry = 0; while (resp == null && retry < 1) { try { resp = x.CancelIndicium(req); // 调用自动生成的连接服务代码 _authToken = resp.Authenticator; } catch (FaultException ex) { // ... 错误处理代码 } catch (Exception ex) { // ... 错误处理代码 } retry++; } return resp; }
连接服务生成的代码(简化版)
[System.Diagnostics.DebuggerStepThroughAttribute()] [System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "4.0.0.0")] [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)] [System.ServiceModel.MessageContractAttribute(WrapperName="CancelIndicium", WrapperNamespace="http://x.com/xml/namespace/2023/07/x/x", IsWrapped=true)] public partial class CancelIndiciumRequest { [System.ServiceModel.MessageBodyMemberAttribute(Namespace="http://x.com/xml/namespace/2023/07/x/x", Order=0)] [System.Xml.Serialization.XmlElementAttribute("Authenticator", typeof(string))] [System.Xml.Serialization.XmlElementAttribute("Credentials", typeof(Credentials))] public object Item; [System.ServiceModel.MessageBodyMemberAttribute(Namespace="http://x.com/xml/namespace/2023/07/x/x", Order=1)] [System.Xml.Serialization.XmlElementAttribute("xTxIDs", typeof(System.Guid[]))] [System.Xml.Serialization.XmlElementAttribute("xNumbers", typeof(string[]))] public object[] Items; [System.ServiceModel.MessageBodyMemberAttribute(Namespace="http://x.com/xml/namespace/2023/07/x/x", Order=2)] [System.Xml.Serialization.XmlElementAttribute(IsNullable=true)] public System.Nullable<bool> SendEmail; public CancelIndiciumRequest() { } public CancelIndiciumRequest(object Item, object[] Items, System.Nullable<bool> SendEmail) { this.Item = Item; this.Items = Items; this.SendEmail = SendEmail; } }
完整异常信息
System.ServiceModel.CommunicationException: There was an error in serializing body of message CancelIndiciumRequest: 'There was an error generating the XML document.'. Please see InnerException for more details. ---> System.InvalidOperationException: There was an error generating the XML document. ---> System.InvalidOperationException: The type System.Guid may not be used in this context. at Microsoft.Xml.Serialization.GeneratedAssembly.XmlSerializationWriterSwsimV135Soap.Write269_CancelIndicium(Object[] p) at Microsoft.Xml.Serialization.GeneratedAssembly.ArrayOfObjectSerializer72.Serialize(Object objectToSerialize, XmlSerializationWriter writer) at System.Xml.Serialization.XmlSerializer.Serialize(XmlWriter xmlWriter, Object o, XmlSerializerNamespaces namespaces, String encodingStyle, String id) --- End of inner exception stack trace --- at System.Xml.Serialization.XmlSerializer.Serialize(XmlWriter xmlWriter, Object o, XmlSerializerNamespaces namespaces, String encodingStyle, String id) at System.ServiceModel.Dispatcher.XmlSerializerOperationFormatter.SerializeBody(XmlDictionaryWriter writer, MessageVersion version, XmlSerializer serializer, MessagePartDescription returnPart, MessagePartDescriptionCollection bodyParts, Object returnValue, Object[] parameters) at System.ServiceModel.Dispatcher.XmlSerializerOperationFormatter.SerializeBody(XmlDictionaryWriter writer, MessageVersion version, String action, MessageDescription messageDescription, Object returnValue, Object[] parameters, Boolean isRequest) --- End of inner exception stack trace --- Server stack trace: at System.ServiceModel.Dispatcher.XmlSerializerOperationFormatter.SerializeBody(XmlDictionaryWriter writer, MessageVersion version, String action, MessageDescription messageDescription, Object returnValue, Object[] parameters, Boolean isRequest) at System.ServiceModel.Dispatcher.OperationFormatter.SerializeBodyContents(XmlDictionaryWriter writer, MessageVersion version, Object[] parameters, Object returnValue, Boolean isRequest) at System.ServiceModel.Dispatcher.OperationFormatter.OperationFormatterMessage.OperationFormatterBodyWriter.OnWriteBodyContents(XmlDictionaryWriter writer) at System.ServiceModel.Channels.BodyWriterMessage.OnWriteBodyContents(XmlDictionaryWriter writer) at System.ServiceModel.Channels.Message.OnWriteMessage(XmlDictionaryWriter writer) at System.ServiceModel.Channels.BufferedMessageWriter.WriteMessage(Message message, BufferManager bufferManager, Int32 initialOffset, Int32 maxSizeQuota) at System.ServiceModel.Channels.TextMessageEncoderFactory.TextMessageEncoder.WriteMessage(Message message, Int32 maxMessageSize, BufferManager bufferManager, Int32 messageOffset) at System.ServiceModel.Channels.HttpOutput.SerializeBufferedMessage(Message message, Boolean shouldRecycleBuffer) at System.ServiceModel.Channels.HttpOutput.Send(TimeSpan timeout) at System.ServiceModel.Channels.HttpChannelFactory`1.HttpRequestChannel.HttpChannelRequest.SendRequest(Message message, TimeSpan timeout) at System.ServiceModel.Channels.RequestChannel.Request(Message message, TimeSpan timeout) at System.ServiceModel.Dispatcher.RequestChannelBinder.Request(Message message, TimeSpan timeout) at System.ServiceModel.Channels.ServiceChannel.Call(String action, Boolean oneway, ProxyOperationRuntime operation, Object[] ins, Object[] outs, TimeSpan timeout) at System.ServiceModel.Channels.ServiceChannelProxy.InvokeService(IMethodCallMessage methodCall, ProxyOperationRuntime operation) at System.ServiceModel.Channels.ServiceChannelProxy.Invoke(IMessage message) Exception rethrown at [0]: at System.Runtime.Remoting.Proxies.RealProxy.HandleReturnMessage(IMessage reqMsg, IMessage retMsg) at System.Runtime.Remoting.Proxies.RealProxy.PrivateInvoke(MessageData& msgData, Int32 type) at USPostal.SWSIM.SwsimV135Soap.CancelIndicium(CancelIndiciumRequest request) at USPostal.StampsApiInterface.GetResponse(CancelIndiciumRequest req) in C:\Users\lawre\Source\Repos\USPostalAPI\USPostal\InterfaceClasses\StampsApiInterface.cs:line 1954
解决方案
问题核心在于对Items属性序列化规则的误解:生成的代码中,Items的XmlElementAttribute指定了允许的元素类型是Guid[]或string[],而非单个Guid或string。也就是说,Items数组中需要存放的是Guid[]对象(对应XML元素<xTxIDs>),而非将每个Guid转成object存入数组。
正确赋值方式
将Guid[]作为一个元素放入object[]中,这样XML序列化器就能匹配到对应的属性配置,正确生成服务端期望的XML结构:
Items = new object[] { new Guid[] { new Guid(trackNum) } }
解释为什么之前的方式错误
- 直接赋值
Guid[]给object[]:编译错误是因为值类型数组(如Guid[])不支持协变转换为object[],只有引用类型数组(如string[])才能隐式转换。 - 将单个
Guid转成object存入数组:运行时错误是因为序列化器找不到单个Guid对应的XML元素定义——属性配置仅允许Guid[]或string[]类型作为Items的元素。
扩展:传入多个Guid的情况
如果需要传入多个Guid,只需扩展内部的Guid[]即可:
Items = new object[] { new Guid[] { new Guid(trackNum1), new Guid(trackNum2) } }
内容的提问来源于stack exchange,提问作者user2832940
相关产品推荐
相关产品推荐

