VBA MSSOAP.SoapClient30 error: Incorrect number of parameters supplied for SOAP request HRESULT=0x80070057 - vba

update: so I've figured I need to somehow submit a complex type at method parameter - how do I do this with VBA?
This is my first time coding VBA and I will appreciate any possible pointers at how I can fix the problem. Basically, I've written a little soap service and it works fine - I test it with SoapUI - so I guess other application should be able to consume it.
The WSDL the service generates is here. Perhaps, it is not too friendly for consuming by VBScript SOAPClient - any points in that direction will help a lot.
I'm trying to put a bit of code together that actually uses it (VBScript below) - I've built it on top of an example I found while googling. It generates the following error:
Incorrect number of parameters supplied for SOAP request HRESULT=0x80070057
Module Module1
Dim WSDLFileName As String
Dim base64attachment As String
Dim attachment_filename As String
Dim summary As String
Dim SoapClient
Dim res
Sub Main()
WSDLFileName = "http://localhost:7777/?wsdl"
base64attachment = "UG9ydG1hbiBpcyBwb3J0Zm9saW8gbWFuYWdlbWVudCBzb2Z0d2FyZSB0byBoZWxwIFBNTyBrZWV"
attachment_filename = "test_file.txt"
summary = "test issue with summary"
SoapClient = CreateObject("MSSOAP.SoapClient30")
SoapClient.MSSoapInit(WSDLFileName)
res = SoapClient.CreateJiraIssueWithBase64Attachment(summary, base64attachment, attachment_filename)
Console.Out.WriteLine(res)
End Sub
End Module
Any pointers will help, I'm lost here.
I'm expecting it should create a response like this:
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:open="open.JiraAdapter">
<soapenv:Header/>
<soapenv:Body>
<open:CreateJiraIssueWithBase64Attachment>
<open:summary>some summary</open:summary>
<open:base64attachment>BASE64CODEDFILE</open:base64attachment>
<open:attachment_filename>NAME of the file attached</open:attachment_filename>
</open:CreateJiraIssueWithBase64Attachment>
</soapenv:Body>
</soapenv:Envelope>

Your service response contains complex type object.
<xs:element name="CreateJiraIssueWithBase64AttachmentResult" type="s0:Status" minOccurs="0" nillable="true"/>
To be able to use complex types you need to use "MSSOAP.SoapSerializer30" to create request and "MSSOAP.SoapReader30" for reading response.
SOAP UI can helps you to see the correct request structure (tags, namespaces and actions).
I think it something like that
Connector = CreateObject("MSSOAP.HttpConnector30")
Connector.Property("EndPointURL") = "url"
Connector.Property("UseSSL") = True
Connector.Connect
Connector.Property("SoapAction") = "CreateJiraIssueWithBase64Attachment"
Connector.BeginMessage
Serializer = CreateObject("MSSOAP.SoapSerializer30")
Serializer.Init(Connector.InputStream)
Serializer.StartEnvelope
Serializer.StartBody
Serializer.StartElement("CreateJiraIssueWithBase64Attachment";"open.jiraAdapter.test")
Serializer.StartElement("summary";"open.jiraAdapter.test")
Serializer.WriteString("another test issue for JUR")
Serializer.EndElement
Serializer.StartElement("base64attachment";"open.jiraAdapter.test")
Serializer.WriteString("Y29kZTogaHR0cDovL3Bhc3RlYmluLmNvbS9EbUx3N0oycQ0KeG1sOiBodHRwOi8vcGFzdGViaW4uY29tLzE3Q2MxVjJM")
Serializer.EndElement
Serializer.StartElement("attachment_filename";"open.jiraAdapter.test")
Serializer.WriteString("readme.txt")
Serializer.EndElement
Serializer.EndElement
Serializer.EndBody
Serializer.EndEnvelope
Connector.EndMessage
Reader = CreateObject("MSSOAP.SoapReader30")
Reader.Load(Connector.OutputStream)
/// Reader.Body.xml - response
Hope this help you.

Related

How to extract SOAP response using pysimplesoap?

I am new on using pysimplesoap. I am succeed using pysimplesoap to generate a soap request to a SOAP server, and the soap server is responded correctly, however, I do not know how to extract the information returned.
This is my code on pysimplesoap for the request
> from pysimplesoap.client import SoapClient
> client = SoapClient(location="http://192.168.206.111:8998/axis2/services/SecurityService", action="", namespace="http://www.labtest.com/Security", ns="ns3")
> response = client.call("login", ("ns3:loginName", "administrator"), ("ns3:password", "admin"))
The SOAP response is in below format.
<soapenv:Envelope
xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
<soapenv:Body>
<n:loginResponse
xmlns:n="http://www.labtest.com/Security"
xmlns:n0="http://www.labtest.com/Types">
<n:errorCode>
<n0:hasError>
false
</n0:hasError>
<n0:status>
STATUS_SUCCESS
</n0:status>
</n:errorCode>
<n:authorizationToken>
<n0:token>
6430303938366138316265646532313138623866353235343030346130653330
</n0:token>
<n0:securityPrivileges>
<n0:values>
<n0:securityAttribute>
SUPER_USER_ACCESS
</n0:securityAttribute>
<n0:accessRights>
<n0:values>
FULL_CONTROL
</n0:values>
</n0:accessRights>
</n0:values>
</n0:securityPrivileges>
</n:authorizationToken>
</n:loginResponse>
</soapenv:Body>
</soapenv:Envelope>
I tried to use the print response or print (response), but nothing show up.
The response object is a pysimplesoap.client.SimpleXMLElement.
Behind the hood, a print(response) will call its __str__() method, the choice have been made, for pysimplesoap that `__str__() returns the text content of the node (if any), if your node contains no text content, like :
<MySoapResponse>
<child tag attr="value />
</MySoapResponse>
… then, __str__() will return nothing, and so do printing.
Alternatively, you may want to
navigate the XML tree of your answer by using SimpleXMLElement methods :
children() to grab childrens list
tag['attr'] (dict notation) to access attributes of an XML tag
tag.get_name() to get a tag name ;
inspect the full answer as a string (including Soap headers) as string calling repr(response), but it's more for debugging purposes.
See also the basic client documentation online.

Can somebody give me an example of getting the content of a page from a URL in vb.net for windows 8?

I am very new to vb/.net and I'm trying to do something that I can do easily in classic vb. I want to get the source html for a webpage from the URL.
I'm using vb.net in Visual Studio Express for Windows 8.
I've read loads of stuff that talk about HttpWebRequest, but I can't get it to work properly.
I did at one point have it returning the html header, but I want to content of the page. Now, I can't even get it back to giving me the header. Ultimately, I want to process the html returned which I'll do (to begin with) the old-fashioned way and process the returned html as a string, but for now I'd like to just get the page.
The code I've got is:
Dim URL As String = "http://www.crayola.com/"
Dim request As System.Net.HttpWebRequest = System.Net.HttpWebRequest.Create(New Uri(URL))
txtHTML.Text = request.GetRequestStreamAsync().ToString()
Can anyone help me with an example to get me going please?
You're trying to use an Async method in a synchronous way, which won't make any sense. If you're using .NET 4.5, you can try marking the calling method with Async and then using the Await keyword when calling GetRequestStreamAsync.
Public Sub MyDownloaderMethod()
Dim URL As String = "http://www.crayola.com/"
Dim request As System.Net.HttpWebRequest
= System.Net.HttpWebRequest.Create(New Uri(URL))
' Use the Await keyword wait for the async task to complete.
Dim response = request.GetResponseAsync()
txtHTML.Text = response.GetResponseStream().ToString()
End Function
See the following MSDN article for more information on async programming with the Await keyword: http://msdn.microsoft.com/en-us/library/vstudio/hh191443.aspx
Edit
You are receiving your error because you're trying to get the Request stream (what you send the server), and what you really want is the Response stream (what the server sends back to you). I've updated my code to get the WebResponse from your WebRequest and then retrieve the stream from that.
Public Shared Function GetWebPageString(ByVal address As Uri) As String
Using client As New Net.WebClient()
Return client.DownloadString(address)
End Using
End Function
There is also DownloadStringAsync if you don't want to block
request.GetRequestStreamAsync() is probably not a method. I think you're cribbing code from a site where someone wrote their own add-on methods to HttpWebRequest. Try request.GetResponse() to return a response object, then in the response object you can inspect the stream and convert it to text if you need to.
This worked for me in VB.Net 4.5
Public Async Sub GetHTML()
Dim PageHTML as string
Dim client As New HttpClient
Dim getStringTask As Task(Of String) = client.GetStringAsync(PageURL)
PageHTML = Await getStringTask
MsgBox(PageHTML)
End Sub

Magento API SOAP v1 and VB.NET

I'm using VB.NET to communicate with Magento via the API SOAP v1. I had it working fine until I got to a call that needed an associative array. I've tried dictionaries, hashtables, custom types, etc. I did read hashtables and dictionaries are not serializable. So I tried the custom type/object/class. Below is the error I received:
The type XXXX was not expected. Use the Xmlinclude or SoapInclude attribute to specify types that are not known statically.
So I've read a lot of posts in regards to the above error and I can't get anything to work. The error seems at least to say what I'm trying is possible if I do it right, but maybe that is not the case. I don't know much about SOAP, but I can see this never working since the web service might not know how to handle the object.
So my question is if it's possible to send a custom object to the Magento API. Or more broadly is it possible to get SOAP v1 to work with VB.NET. I know v2 is an option but I'm pretty familiar with v1 and already having it working in VB.NET other than this scenario.
Answering a question you didn't ask — but have you considered using the XML-RPC adapter for the V1 API? It exposes the same exact methods as the SOAP API, but since XML-RPC doesn't have the same strong concept of types that SOAP does you may be able to get a generic object through from .NET (said without being that familiar with .NET SOAP or XML-RPC libraries)
It took a lot of digging, but I have it all working. To start I used the PHP SoapClient and noted how it formed associative arrays in the soap request. You can trace requests and responses, pretty handy. From there I wrote my own soap client in VB.NET using a WebRequest object. In doing so I have full control over the xml being sent to the API.
Again the reason I went down this road is ultimately V2 was not working for me. For some reason not all parameters were making it to the API. That and the fact I'm pretty comfortable with V1 too. I've written several custom APIs.
I apologize for the brevity, but there is a lot that went into this. Probably most of my time was hitting multiple dead ends. If anyone wants specifics feel free email me.
EDIT:
Here is the php code I used to see how I needed to format the requests:
$client = new SoapClient('http://www.site.com/index.php/api/soap/?wsdl',array('trace' => TRUE));
$session = $client->login('user','api-key');
echo $client->__getLastRequest() ."\n\n";
echo $client->__getLastRequestHeaders() ."\n\n";
echo $client->__getLastResponse() ."\n\n";
echo $client->__getLastResponseHeaders() ."\n\n";
$result = $client->call($session, 'cataloginventory_stock_item.list','393');
echo $client->__getLastRequest() ."\n\n";
echo $client->__getLastRequestHeaders() ."\n\n";
var_dump($result);
$client->endSession($session);
Below is how to send the request using VB.NET. You will need to construct the XML/SOAP body using the php above as a guide. I made a class per API call which output the needed XML. You will need System.Net, System.Xml & System.IO. I used getSoapHeader() because there is some common XML that goes into a request. See next code section for more details:
Private Function makeSoapRequest(ByVal soapBody As String) As String
Dim req As WebRequest = WebRequest.Create(_soap_url)
Dim xml As String
xml = getSoapHeader() & soapBody
Dim buffer() As Byte = System.Text.Encoding.UTF8.GetBytes(xml)
req.ContentType = "text/xml; charset=utf-8"
req.Method = "POST"
req.Headers.Add("SOAPAction", "urn:Mage_Api_Model_Server_HandlerAction")
req.ContentLength = buffer.Length
Dim st As System.IO.Stream = req.GetRequestStream
st.Write(buffer, 0, buffer.Length)
st.Close()
Dim response As WebResponse
Try
response = req.GetResponse
Catch ex As WebException
response = ex.Response
End Try
st = response.GetResponseStream()
Dim reader As New StreamReader(st)
Dim responseFromServer As String = reader.ReadToEnd()
makeSoapRequest = responseFromServer
response.Close()
st.Close()
End Function
Below is the getSoapHeader() function. As noted the ns2 portion is only needed if you are using type="ns2:Map" which is what I needed for associative arrays:
Private Function getSoapHeader() As String
'ns2 is not always needed
getSoapHeader = "<?xml version=""1.0"" encoding=""UTF-8""?><SOAP-ENV:Envelope xmlns:SOAP-ENV=""http://schemas.xmlsoap.org/soap/envelope/"" xmlns:ns1=""urn:Magento"" xmlns:xsd=""http://www.w3.org/2001/XMLSchema"" xmlns:xsi=""http://www.w3.org/2001/XMLSchema-instance"" xmlns:SOAP-ENC=""http://schemas.xmlsoap.org/soap/encoding/"" xmlns:ns2=""http://xml.apache.org/xml-soap"" SOAP-ENV:encodingStyle=""http://schemas.xmlsoap.org/soap/encoding/""> " & vbCrLf
End Function

Passing a string param to a RESTful service during POST action

I am having a RESTful service with the following method:
[WebInvoke]
string GetDataFromStringAsString(string xmlString);
My client call to the method is as below:
var client = new RestClient();
client.BaseUrl = serviceBaseUrl;
var request = new RestRequest(method){RequestFormat = DataFormat.Xml};
request.Resource = resourceUrl;
request.AddParameter("text/xml", requestBody,
ParameterType.RequestBody);
var response = client.Execute(request);
Let us take a string to post as "Hello World".
Now the string that i post to the above method gives me a 400 Bad
request. In order to get it working i had to wrap the above string in
a element as shown below:
<string xmlns="http://schemas.microsoft.com/2003/10/
Serialization/">Hello World</string>
Now when i post the above string i get a success response back from
the server.
Why is that i have to manually wrap the string to make it work. Is
there a way that i can achieve to post a string without doing the
above manually.
The only other way that I am aware of is to use stream as your input parameter. e.g.
[WebInvoke]
string GetDataFromStringAsString(stream xmlString);
The problem with .Net 4 WCF REST is that fundamentally WCF only knows how to pass two types of info, either XML or a stream of bytes. Personally, I would use WCF Web API instead of the standard WCF REST library because you are going run into lots more of these kinds of issues.

Manually deserialize WebRequest XML

SO I have an ASMX web service that returns a array of Search Result objects. When I call the WebMethod via the browser, the following XML is generated...
<?xml version="1.0" encoding="utf-8"?><ArrayOfSearchResult xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://tempuri.org/"><SearchResult>
<Name>Rock Salt Steak House</Name>
<BusinessType>Steakhouses</BusinessType>
<Rating>mStar30</Rating>
<Address>1232 Westlake Ave N</Address>
<City>Seattle</City>
<State>WA</State>
<Phone>(206) 284-1047</Phone>
<Zip>98109</Zip></SearchResult><SearchResult>
<Name>Laredos Grill</Name>
<BusinessType>Tex-Mex Bars</BusinessType>
<Rating>mStar35</Rating>
<Address>555 Aloha St Ste 100</Address>
<City>Seattle</City>
<State>WA</State>
<Phone>(206) 218-1040</Phone>
<Zip>98109</Zip></SearchResult>.......
This XML gets saved in a file to be de-serialized later. The problem is I can't seem to get it serialized again. Here's the code I use....
XmlSerializer serializer = new XmlSerializer(typeof(List<Service.SearchResult>));
using (StringReader stringReader = new StringReader(strXMLContent)) // can throw ArgumentNullException
{
using (XmlReader xmlReader = XmlReader.Create(stringReader))
{
//xmlReader.Read();
return ((List<Service.SearchResult>)serializer.Deserialize(xmlReader)).ToArray(); // can throw SerializationException
}
}
The error I get is complaining about "there is an error in xml document (2,2)" and the inner exception is (InnerException = {"ArrayOfSearchResult xmlns='http://tempuri.org/' was not expected."})
Of course when calling this WebMethod in code the collection comes down easily. It isn't until I try to manually deserialize later that it's get's mad.
Any ideas would be greatly appreciated...
Thanks!
First, why are you calling it via WebRequest? Why not just use "Add Service Reference" and use the proxy class?
Secondly, when you're calling it in the browser, you're not using SOAP. Note the lack of SOAP Envelope in the response.