WinMo > ASMX WebException - how to get details? - web-services

Okay, we've got an application which consists of a website hosting several ASMX webservices, and a handheld application running on WinMo 6.1 which calls the webservices.
Been developing in the office, everything works perfect.
Now we've gone to install it at the client's and we got all the servers set up and the handhelds installed. However the handhelds are now no longer able to connect to the webservice.
I added in extra code in my error handler to specifically trap WebException exceptions and handle them differently in the logging to put out extra information (.Status and .Response).
I am getting out the status, which is returning a [7], or ProtocolError. However when I try to read out the ResponseStream (using WebException.Response.GetResponseStream), it is returning a stream with CanRead set to False, and I thus am unable to get any further details of what is going wrong.
So I guess there are two things I am asking for help with...
a) Any help with trying to get more information out of the WebException?
b) What could be causing a ProtocolError exception?
Things get extra complicated by the fact that the client has a full-blown log-in-enabled proxy setup going on-site. This was stopping all access to the website initially, even from a browser. So we entered in the login details in the network connection for HTTP on the WinMo device. Now it can get to websites fine.
In fact, I can even pull up the webservice fine and call the methods from the browser (PocketIE). So I know the device is able to see the webservices okay via HTTP. But when trying to call them from the .NET app, it throws ProtocolError [7].
Here is my code which is logging the exception and failing to read out the Response from the WebException.
Public Sub LogEx(ByVal ex As Exception)
Try
Dim fn As String = Path.Combine(ini.CorePath, "error.log")
Dim t = File.AppendText(fn)
t.AutoFlush = True
t.WriteLine(<s>===== <%= Format(GetDateTime(), "MM/dd/yyyy HH:mm:ss") %> =====<%= vbCrLf %><%= ex.Message %></s>.Value)
t.WriteLine()
t.WriteLine(ex.ToString)
t.WriteLine()
If TypeOf ex Is WebException Then
With CType(ex, WebException)
t.WriteLine("STATUS: " & .Status.ToString & " (" & Val(.Status) & ")")
t.WriteLine("RESPONSE:" & vbCrLf & StreamToString(.Response.GetResponseStream()))
End With
End If
t.WriteLine("=".Repeat(50))
t.WriteLine()
t.Close()
Catch ix As Exception : Alert(ix) : End Try
End Sub
Private Function StreamToString(ByVal s As IO.Stream) As String
If s Is Nothing Then Return "No response found."
// THIS IS THE CASE BEING EXECUTED
If Not s.CanRead Then Return "Unreadable response found."
Dim rv As String = String.Empty, bytes As Long, buffer(4096) As Byte
Using mem As New MemoryStream()
Do While True
bytes = s.Read(buffer, 0, buffer.Length)
mem.Write(buffer, 0, bytes)
If bytes = 0 Then Exit Do
Loop
mem.Position = 0
ReDim buffer(mem.Length)
mem.Read(buffer, 0, mem.Length)
mem.Seek(0, SeekOrigin.Begin)
rv = New StreamReader(mem).ReadToEnd()
mem.Close()
End Using
Return rv.NullOf("Empty response found.")
End Function
Thanks in advance!

I was not able to get any more information out of the WebException class. For some reason that GetResponseStream always returns an unreadable stream.
I was able to narrow the problem down to proxy authentication though by writing a separate little program which simply tried to request a web page and read the response and put it into a textbox.
This program returned a response of proxy authentication required. I find this really weird though because I put the proxy information into the network connection settings on my device. I would've though this would apply to all network traffic going out on that connection; apparently it only applies to traffic through the browser, not application requests. Odd.

Related

How to consume SOAP Webservices in Blackberry

I am working on a blackberry application. I need to call soap webservices, but I am unable to do so, and am getting null as a response. Following is my code:
private static final String CONNECTION_PARAMS = ";deviceside=true";
SoapObject request = new SoapObject("http://service.action.com/",
"findActiveSecurities");
SoapSerializationEnvelope envelope = new SoapSerializationEnvelope(SoapEnvelope.VER11);
envelope.bodyOut = request;
HttpTransportBasicAuth ht =
new HttpTransportBasicAuth("http://myurl.com/ebclient/services/MobileClientService?wsdl"+CONNECTION_PARAMS,
"myusername",
"mypassword");
PropertyInfo propInfo=new PropertyInfo();
propInfo.type=PropertyInfo.INTEGER_CLASS;
//adding parameters
request.addProperty("arg0","NSE");
request.addProperty("arg1","0");
request.addProperty("arg2","100");
envelope.setOutputSoapObject(request);
try {
ht.call(SOAP_ACTION, envelope);
result = (SoapObject)envelope.getResponse();
System.out.println(result);
} catch (IOException e) {
e.printStackTrace();
} catch (XmlPullParserException e) {
e.printStackTrace();
}
I am getting null as a result.Please have a look at the code and help me to correct it.
Thanks in advance
Actually the problem was instead of passing 0 and 100 as String ...
request.addProperty("arg0","NSE");
request.addProperty("arg1","0");
request.addProperty("arg2","100");
I use
request.addProperty("arg0","NSE");
request.addProperty("arg1",new Integer(0));
request.addProperty("arg2",new Integer(1000));
also this link helped me.
also before asking this question I was facing some problem that the Simulator was not recognizing a Library. It shows error message something like "there is no library Ksoap2_j2me.jar" - resolved from this link.
Sorry for poor English but I think this can save time of some other developer.
It's hard to tell from what you're posted, but my guess is that you're having some kind of network problem. I'm guessing that you initialize result = null;, and then your call to ht.call() throws an IOException, leaving result null.
You're using ksoap2, which is a library written for generic J2ME clients. However, BlackBerry networking doesn't work exactly like all other J2ME platforms.
You are controlling the BlackBerry network transport with your connection params string, which is hardcoded:
private static final String CONNECTION_PARAMS = ";deviceside=true";
Unfortunately, this string suffix may not be right for all network conditions (or any, if you don't have device APN settings correct).
I think you have a couple choices:
1. Connection Suffix Strings
You can try dynamically choosing the right suffix string, depending on conditions when your app runs. This can allow the device, for example, to connect via Wi-Fi if it's available, or via BES if that's available. Developers new to BlackBerry may be surprised that app code needs to worry about this (read here for more, or watch this).
If you want to simply replace CONNECTION_PARAMS with a dynamic string, you might check out the implementation here.
2. ConnectionFactory
In OS 5.0, BlackBerry added the ConnectionFactory class, which was a big improvement over the old way of having to assemble connection strings. If you only need to support OS 5.0 and greater, you might choose to rewrite the code to use ConnectionFactory.
Since you have access to the ksoap source code, you could change it. It looks like the connection code is in ServiceConnectionMidp.java:
public ServiceConnectionMidp(String url) throws IOException {
connection = (HttpConnection) Connector.open(url, Connector.READ_WRITE, true);
}
Instead of attaching connection parameters to the url passed to this class, you could change the class to get the connection from a ConnectionFactory, customized to support the network transports you want.
Doing this means that if you ever want to update your code to use a new version of ksoap2, you'll need to make these modifications again. However, given the future of BlackBerry Java, that seems like a reasonable compromise to make.

Connect to web service in MS Access with VBA

Is it possible to connect to a web service (for example send a HTTP Request) via VBA in Microsoft Access?
For example, the user clicks a button on a form, then a HTTP Request is sent to a web service that responds with OK.
Has anyone done this before?
Note: VBA, not VB.NET.
This is code I've used quite successfully with Access 2003. It's from the interwebs, copied and re-copied ages ago. It creates a XMLHttpRequest Object, sends an HTTP GET request, and returns the results as a string.
Public Function http_Resp(ByVal sReq As String) As String
Dim byteData() As Byte
Dim XMLHTTP As Object
Set XMLHTTP = CreateObject("MSXML2.XMLHTTP")
XMLHTTP.Open "GET", sReq, False
XMLHTTP.send
byteData = XMLHTTP.responseBody
Set XMLHTTP = Nothing
http_Resp = StrConv(byteData, vbUnicode)
End Function
sReq is the URL; the function returns the response. You may need to make sure ActiveX Data Objects are enabled under your References (in the VBA editor, go to Tools > References).
This is the code , which I used. You need to first reference Microsoft XML V6 for this code to work.
Public Sub GetPerson()
'For API
Dim reader As New XMLHTTP60
reader.Open "GET", "www.exmple.com/users/5428a72c86abcdee98b7e359", False
reader.setRequestHeader "Accept", "application/json"
reader.send
Do Until reader.ReadyState = 4
DoEvents
Loop
If reader.Status = 200 Then
Msgbox (reader.responseText)
Else
MsgBox "Unable to import data."
End If
End Sub
I have used the "Microsoft Office 2003 Web Services Toolkit 2.01" toolkit (available here) on a few projects. It worked pretty well for me, although I also wrote the web services it was talking to, so I had the luxury of being able to fiddle with both ends of the process when getting it to actually work. :)
In fact, I just upgraded one of those apps from Access_2003 to Access_2010 and the SOAP client part of the app continued to work without modification. However, I did encounter one wrinkle during pre-deployment testing:
My app would not compile on a 64-bit machine running 32-bit Office_2010 because it did not like the early binding of the SoapClient30 object. When I switched to using late binding for that object the code would compile, but it did not work. So, for that particular app I had to add a restriction that 64-bit machines needed to be running 64-bit Office.
Also, be aware that Microsoft's official position is that "All SOAP Toolkits have been replaced by the Microsoft .NET Framework." (ref. here).

Trouble Getting Data from a Webservice using Qooxdoo

My capstone team has decided to use Qooxdoo as the front end for our project. We're developing apps for OpenFlow controllers using NOX, so we're using the NOX webservices framework. I'm having trouble getting data from the service; I know the service is running because if I go to the URL using Firefox the right data shows up. Here's the relevant portion of my code:
var req = new qx.io.remote.Request("http://localhost/ws.v1/hello/world",
"GET", "text/plain");
req.addListener("complete", function(e) {
this.debug(e.getContent());
});
var get = new qx.ui.form.Button("get");
get.addListener("execute", function() {
alert("The button has been pressed");
req.send();
}, this);
form.addButton(get);
In the firebug console I get this message after I click through the alert:
008402 qx.io.remote.Exchange: Unknown status code: 0 (4)
And if I press the Get button again I get this error:
027033 qx.io.remote.transport.XmlHttp[56]: Failed with exception: [Exception... "Component returned failure code: 0x80070057 (NS_ERROR_ILLEGAL_VALUE) [nsIXMLHttpRequest.open]" nsresult: "0x80070057 (NS_ERROR_ILLEGAL_VALUE)" location: "JS frame :: file:///home/user/qooxdoo-1.0-sdk/framework/source/class/qx/io/remote/transport/XmlHttp.js :: anonymous :: line 279" data: no]
I've also looked at the Twitter Client tutorial, however the "dataChange" event I set up in place of the "tweetsChanged" event never fired. Any help is appreciated, thank you.
This sound like a cross domain request issue. qx.io.remote.Request uses XHR for transporting the data which may not work in every case due to the browser restriction. Switching the crossDomain flag on the request to true will change from XHR to a dynamically inserted script tag doesn't have the cross domain restriction (but other restrictions).
req.setCrossDomain(true);
Maybe that solves your problem.
Additionally, you can take a look at the documentation of the remote package to get some further details on cross domain requests:
http://demo.qooxdoo.org/current/apiviewer/#qx.io.remote
Also take care not to use a request object twice. The only work once.

How do I debug mangled soap requests?

Lately, we've been seeing exceptions like this in our .NET (.asmx) webservices:
System.Web.Services.Protocols.SoapException: Server was unable to read request. ---> System.InvalidOperationException: There is an error in XML document (868, -3932). ---> System.Xml.XmlException: '.', hexadecimal value 0x00, is an invalid character. Line 868, position -3932.
at System.Xml.XmlTextReaderImpl.Throw(Exception e)
at System.Xml.XmlTextReaderImpl.Throw(String res, String[] args)
at System.Xml.XmlTextReaderImpl.Throw(Int32 pos, String res, String[] args)
at System.Xml.XmlTextReaderImpl.ThrowInvalidChar(Int32 pos, Char invChar)
at System.Xml.XmlTextReaderImpl.ParseNumericCharRefInline(Int32 startPos, Boolean expand, BufferBuilder internalSubsetBuilder, Int32& charCount, EntityType& entityType)
at System.Xml.XmlTextReaderImpl.ParseText(Int32& startPos, Int32& endPos, Int32& outOrChars)
at System.Xml.XmlTextReaderImpl.ParseText()
at System.Xml.XmlTextReaderImpl.ParseElementContent()
at System.Xml.XmlTextReaderImpl.Read()
at System.Xml.XmlTextReader.Read()
at System.Web.Services.Protocols.SoapServerProtocol.SoapEnvelopeReader.Read()
at System.Xml.XmlReader.ReadElementString()
at Microsoft.Xml.Serialization.GeneratedAssembly.XmlSerializationReader1.Read14_SendErrlog()
at Microsoft.Xml.Serialization.GeneratedAssembly.ArrayOfObjectSerializer12.Deserialize(XmlSerializationReader reader)
at System.Xml.Serialization.XmlSerializer.Deserialize(XmlReader xmlReader, String encodingStyle, XmlDeserializationEvents events)
--- End of inner exception stack trace ---
at System.Xml.Serialization.XmlSerializer.Deserialize(XmlReader xmlReader, String encodingStyle, XmlDeserializationEvents events)
at System.Xml.Serialization.XmlSerializer.Deserialize(XmlReader xmlReader, String encodingStyle)
at System.Web.Services.Protocols.SoapServerProtocol.ReadParameters()
--- End of inner exception stack trace ---
at System.Web.Services.Protocols.SoapServerProtocol.ReadParameters()
at System.Web.Services.Protocols.WebServiceHandler.CoreProcessRequest()
How can I debug this exception? This exception is getting reported to us from a SOAP filter which looks for exceptions in message.Stage = SoapMessageStage.AfterSerialize.
Is there any way to get at the original soap request? How do I get an invalid character at line 868, column -3932? How can there a negative column 3932?
This is one of the irritating things about the Microsoft web services approach -- if the request cannot be deserialized into the objects in your web method signature then the service consumer gets a cryptic message. And to top it off, the request never makes it into your web service because it cannot be deserialzied so you can't handle the error gracefully.
What I would do to help with these types of issues is to create a new SoapExtension that simply lets you output the raw XML to a destination that is convenient for you (file or Trace to be read by DebugView or whatever else you like). The code would go in the BeforeDeserialize stage. You could enable the SoapExtension via web.config in the event you wanted to investigate one of these issues. The downside of using the web.config to add the SoapExtension is that it will be active for the entire web application. You could add some additional custom configuration that would allow your service to only log information for a specific endpoint or a specific web method if you wanted.
Usually, just by seeing the incoming XML you can see what the problem is. If not, then you could try to manually run the captured XML through small program that invokes the XML serializer and see if you can find out what is going on. Another useful tool is Web Service Studio 2 which is a test harness which lets you enter data and invoke your service (and also submit any XML you want).
In terms of your specific issue, here is my take/guess. It looks like ASCII character null is getting encoded and sent to your service which is invalid according to the XML Spec. The simple answer is not to send that character. But who is sending that character? Is it a .NET client? Do you have control over the client? If you need to work around someone else's bug, then you may have to replace the offending character(s) with another character (perhaps empty string).
You should be able to get the original message by using another SoapExtension. In fact, the same extension could probably be modified to make a copy of the input, and to discard it if there is no exception. The original input would then be available to you if an exception occurred.
You could also use an external tool like Fiddler to watch what's being sent to you.
FYI: SoapException.Message is intentionally left vague to prevent exposing too much information which could potentially be used to exploit the system.
For your particular case I'd take John's advice and install Fiddler to monitor the actual HTTP traffic and view the message on the wire.
The portion of your exception that jumps out at me is the "hexadecimal value 0x00, is an invalid character" but as you mentioned the line number it points to is bunk--so it's nothing concrete.
What kind of parameters do you pass to the service? Are you doing any kind of custom encoding with a SOAP extension? Any additional SOAP headers being added?

"Class does not support automation" error when i call Request.ServerVariables("remote_host")

I'm in the process of writing a basic cookie for an ecommerce site which is going to store the user's IP among other details.
We'll then record the pages they view in the database and pull out a list of recently viewed pages.
However i'm having an issue with the following code.
dim caller
caller = Response.Cookies("caller")
if caller = "" then
caller = Request.ServerVariables("remote_host")
end if
On running this, i get the following error message.
"Sun ONE ASP VBScript runtime (0x800A01AE)
Class does not support automation"
Any ideas? Google has nothing obvious.
Should be Request.Cookies when checking the value.:
dim caller
caller = Request.Cookies("caller")
if caller = "" then
caller = Request.ServerVariables("remote_host")
end if