Доброго дня, встречались тут спецы по битриксу, если токовые имеются, прошу помощи в формировании ответа на соап запрос.
Требуется реализовать веб-сервис внешней аутентификации с помощью соап во внешней системе через сайт на битрексе. У сервиса 3 метода, два из трех реализованы, с одним уже всю голову сломал, ТП битрикса комментариев по модулю веб-сервисов не дает, ссылается на доку, на форуме битриксов тоже тишина, может тут кто поможет.
Необходимо по имени пользователя вернуть массив данных данного пользователя в ответе, загвоздка в том что одино из возвращаемых значений является массивом. В документации по веб-сервисам и примерах кода которые удалось найти в недрах битрикса описано как передать массив во входящем параметре, а мне нужен ответ.
Структура запроса в соапуи выглядит так
<FindConsumer>
<login>c22314056</login>
</FindConsumer>
ответа
<pyr:FindConsumerResponse>
<!--Optional:-->
<pyr:FindConsumerResult>
<!--Optional:-->
<pyr:Address>?</pyr:Address>
<!--Optional:-->
<pyr:ContractEndDt>?</pyr:ContractEndDt>
<!--Optional:-->
<pyr:ContractNumber>?</pyr:ContractNumber>
<!--Optional:-->
<pyr:ContractStartDt>?</pyr:ContractStartDt>
<!--Optional:-->
<pyr:Email>?</pyr:Email>
<!--Optional:-->
<pyr:INN>?</pyr:INN>
<!--Optional:-->
<pyr:Meters>
<!--Zero or more repetitions:-->
<pyr:ArrayOfMeterData>
<!--Optional:-->
<pyr:Model>?</pyr:Model>
<!--Optional:-->
<pyr:Serial>?</pyr:Serial>
</pyr:ArrayOfMeterData>
</pyr:Meters>
<!--Optional:-->
<pyr:PersonalAccount>?</pyr:PersonalAccount>
<!--Optional:-->
<pyr:Phone>?</pyr:Phone>
</pyr:FindConsumerResult>
</pyr:FindConsumerResponse>
Согласно документации классы и структуры описаны таким образом:
$wsdesc->structTypes["CustomConsumerData"] =
array(
"Address" => array("varType" => "string", "nillable" => "true", "strict" => "no"),
"ContractEndDt" => array("varType" => "string", "nillable" => "true", "strict" => "no"),
"ContractNumber" => array("varType" => "string", "nillable" => "true", "strict" => "no"),
"ContractStartDt" => array("varType" => "string", "nillable" => "true", "strict" => "no"),
"Email" => array("varType" => "string", "nillable" => "true", "strict" => "no"),
"INN" => array("varType" => "string", "nillable" => "true", "strict" => "no"),
"Meters" => array("varType" => "ArrayOfMeterData", "arrType" => "MeterData", "nillable" => "true"),
"PersonalAccount" => array("varType" => "string", "nillable" => "true", "strict" => "no"),
"Phone" => array("varType" => "string", "nillable" => "true", "strict" => "no")
);
$wsdesc->structTypes["ArrayOfMeterData"] =
array(
"MeterData" => array("varType" => "MeterData", "arrType" => "MeterData", "maxOccurs" => "unbounded", "nillable" => "true"),
);
$wsdesc->structTypes["MeterData"] =
array(
"Model" => array("varType" => "string", "nillable" => "true", "strict" => "no"),
"Serial" => array("varType" => "string", "nillable" => "true")
);
$wsdesc->structTypes["NaturalPersonConsumerData"] =
array(
"FirstName" => array("varType" => "string", "nillable" => "true", "strict" => "no"),
"LastName" => array("varType" => "string", "nillable" => "true", "strict" => "no"),
"MidleName" => array("varType" => "string", "nillable" => "true", "strict" => "no"),
"PassportData" => array("varType" => "string", "nillable" => "true", "strict" => "no")
);
$wsdesc->structTypes["LegalEntityConsumerData"] =
array(
"LegalEntityCaption" => array("varType" => "string", "nillable" => "true", "strict" => "no"),
"OGRNIP" => array("varType" => "string", "nillable" => "true", "strict" => "no"),
"DateEGRIP" => array("varType" => "string", "nillable" => "true", "strict" => "no")
);
$wsdesc->classes = array(
"IExternalAuthProvider" => array(
"FindConsumer" => array(
"type" => "public",
"name" => "FindConsumer",
"input" => array(
"login" =>array("varType" => "string", "nillable" => "true"),
),
"output" => array(
"FindConsumerResult" => array("varType" => "CustomConsumerData", "nillable" => "true")
)
),
"ValidatePassword" => array(
"type" => "public",
"name" => "ValidatePassword",
"input" => array(
"login" =>array("varType" => "string"),
"password" =>array("varType" => "string")
),
"output" => array(
"ValidatePasswordResult" => array("varType" => "bool")
)
),
"ValidateSession" => array(
"type" => "public",
"name" => "ValidateSession",
"input" => array(
"sessionId" =>array("varType" => "string", "nillable" => "true")),
"output" => array(
"ValidateSessionResult" => array("varType" => "string")
)
)
)
);
return $wsdesc;
}
При вызове метода FindConsumer в соапуи получаю
<soap:Body>
<soap:Fault>
<faultcode>Server Error</faultcode>
<faultstring>Request has not enough params of strict type to be decoded.</faultstring>
</soap:Fault>
</soap:Body>
Внутренние тесты битрикса в данном случае игнорируют исключение и возвращают массив значений без meters
Внешняя система при обращении к этому методу выкидывает исключение
System.ServiceModel.Dispatcher.NetDispatcherFaultException: The formatter threw an exception while trying to deserialize the message: There was an error while trying to deserialize parameter PyramidExternalAuth:FindConsumerResult. The InnerException message was 'Error in line 1 position 211. 'EndElement' 'FindConsumerResult' from namespace 'PyramidExternalAuth' is not expected. Expecting element 'Address | ContractEndDt | ContractNumber | ContractStartDt | Email | INN | Meters'.'. Please see InnerException for more details.
---> System.Runtime.Serialization.SerializationException: Error in line 1 position 211. 'EndElement' 'FindConsumerResult' from namespace 'PyramidExternalAuth' is not expected. Expecting element 'Address | ContractEndDt | ContractNumber | ContractStartDt | Email | INN | Meters'.
at System.Runtime.Serialization.XmlObjectSerializerReadContext.ThrowRequiredMemberMissingException(XmlReaderDelegator xmlReader, Int32 memberIndex, Int32 requiredIndex, XmlDictionaryString[] memberNames)
at ReadCustomConsumerDataFromXml(XmlReaderDelegator , XmlObjectSerializerReadContext , XmlDictionaryString[] , XmlDictionaryString[] )
at System.Runtime.Serialization.ClassDataContract.ReadXmlValue(XmlReaderDelegator xmlReader, XmlObjectSerializerReadContext context)
at System.Runtime.Serialization.XmlObjectSerializerReadContext.ReadDataContractValue(DataContract dataContract, XmlReaderDelegator reader)
at System.Runtime.Serialization.XmlObjectSerializerReadContext.InternalDeserialize(XmlReaderDelegator reader, String name, String ns, Type declaredType, DataContract& dataContract)
at System.Runtime.Serialization.XmlObjectSerializerReadContext.InternalDeserialize(XmlReaderDelegator xmlReader, Type declaredType, DataContract dataContract, String name, String ns)
at System.Runtime.Serialization.DataContractSerializer.InternalReadObject(XmlReaderDelegator xmlReader, Boolean verifyObjectName, DataContractResolver dataContractResolver)
at System.Runtime.Serialization.XmlObjectSerializer.ReadObjectHandleExceptions(XmlReaderDelegator reader, Boolean verifyObjectName, DataContractResolver dataContractResolver)
at System.Runtime.Serialization.DataContractSerializer.ReadObject(XmlDictionaryReader reader, Boolean verifyObjectName)
at System.ServiceModel.Dispatcher.DataContractSerializerOperationFormatter.PartInfo.ReadObject(XmlDictionaryReader reader, XmlObjectSerializer serializer)
at System.ServiceModel.Dispatcher.DataContractSerializerOperationFormatter.PartInfo.ReadObject(XmlDictionaryReader reader)
at System.ServiceModel.Dispatcher.DataContractSerializerOperationFormatter.DeserializeParameterPart(XmlDictionaryReader reader, PartInfo part, Boolean isRequest)
--- End of inner exception stack trace ---
at System.ServiceModel.Dispatcher.DataContractSerializerOperationFormatter.DeserializeParameterPart(XmlDictionaryReader reader, PartInfo part, Boolean isRequest)
at System.ServiceModel.Dispatcher.DataContractSerializerOperationFormatter.DeserializeBody(XmlDictionaryReader reader, MessageVersion version, String action, MessageDescription messageDescription, Object[] parameters, Boolean isRequest)
at System.ServiceModel.Dispatcher.OperationFormatter.DeserializeBodyContents(Message message, Object[] parameters, Boolean isRequest)
at System.ServiceModel.Dispatcher.OperationFormatter.DeserializeReply(Message message, Object[] parameters)
at System.ServiceModel.Dispatcher.ProxyOperationRuntime.AfterReply(ProxyRpc& rpc)
at System.ServiceModel.Channels.ServiceChannel.HandleReply(ProxyOperationRuntime operation, ProxyRpc& rpc)
at System.ServiceModel.Channels.ServiceChannel.Call(String action, Boolean oneway, ProxyOperationRuntime operation, Object[] ins, Object[] outs, TimeSpan timeout)
at System.ServiceModel.Channels.ServiceChannelProxy.InvokeService(MethodCall methodCall, ProxyOperationRuntime operation)
at System.ServiceModel.Channels.ServiceChannelProxy.Invoke(MethodInfo targetMethod, Object[] args)
--- End of stack trace from previous location where exception was thrown ---
at System.Reflection.DispatchProxyGenerator.Invoke(Object[] args)
at generatedProxy_2.FindConsumer(String )
at CSSecurityManager.Auth.ExternalV2.ExternalAuthProviderClient.Proxy.FindConsumer(String login) in /home/user/p2/Sources/Pyramid/ControlService/CSLinkedAssemblies/CSSecurityManager/Auth/ExternalV2/ExternalAuthProviderClient.cs:line 125