8

I'm trying to consume a Webservice already existing and that works perfectly. After having read many tutorials and examples, I finally managed to get an answer from the server:

Server was unable to process request. Object reference not set to an instance of an object

The WS simply allows you to get and ID from an NT login (one string param, one string answer).

Here is my perl script:

#!perl -w
use strict;
use warnings;

use LWP::UserAgent; 
use SOAP::Lite on_action => sub { "$_[0]$_[1]"; };
use LWP::Debug; LWP::Debug::level('+'); SOAP::Lite->import(+trace => 'all');
#use SOAP::Lite  +trace =>  'debug';
#sub SOAP::Transport::HTTP::Client::get_basic_credentials { return ('user' => 'pwd') };
use Data::Dumper;

my $var = SOAP::Data->new(name => 'NTLogin', value => "1234", type =>'s:string');

my $resultLogin = SOAP::Lite
  -> uri('http://xxxxx')
  -> proxy('http://yyyyy/zzzzz/directory.asmx')
  -> on_action( sub { join '/', @_ } )
  -> GetUIDFromNTLogin($var);

print "lets test it...\n\n";

  print $resultLogin;
  print "\nresult():\n";
  print $resultLogin->result();

And here's the output:

Launching NT to UID conversion
SOAP::Data::new: ()
SOAP::Lite::new: ()
LWP::UserAgent::new: ()
SOAP::Transport::HTTP::Client::new: ()
SOAP::Lite::call: ()
SOAP::Serializer::envelope: ()
SOAP::Serializer::envelope: GetUIDFromNTLogin SOAP::Data=HASH(0x______)
SOAP::Data::new: ()
SOAP::Data::new: ()
SOAP::Data::new: ()
SOAP::Data::new: ()
SOAP::Data::new: ()
SOAP::Transport::HTTP::Client::send_receive: HTTP::Request=HASH(0x______)
SOAP::Transport::HTTP::Client::send_receive: POST http://yyyyy/zzzzz/directory.asmx
Accept: text/xml
Accept: multipart/*
Content-Length: 534
Content-Type: text/xml; charset=utf-8
SOAPAction: http://tempuri.org/GetUIDFromNTLogin

<?xml version="1.0" encoding="UTF-8"?><SOAP-ENV:Envelope xmlns:xsi="http://www.w
3.org/1999/XMLSchema-instance" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/e
ncoding/" xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="
http://www.w3.org/1999/XMLSchema" SOAP-ENV:encodingStyle="http://schemas.xmlsoap
.org/soap/encoding/"><SOAP-ENV:Body><namesp1:GetUIDFromNTLogin xmlns:namesp1="ht
tp://tempuri.org"><NTLogin xsi:type="s:string">1234</NTLogin></namesp1:
GetUIDFromNTLogin></SOAP-ENV:Body></SOAP-ENV:Envelope>
LWP::UserAgent::request: ()
LWP::UserAgent::send_request: POST http://yyyyy/zzzzz/directory.asmx
LWP::UserAgent::_need_proxy: Not proxied
LWP::Protocol::http::request: ()
LWP::Protocol::collect: read 441 bytes
LWP::UserAgent::request: Simple response: Internal Server Error
SOAP::Transport::HTTP::Client::send_receive: HTTP::Response=HASH(0x______)
SOAP::Transport::HTTP::Client::send_receive: HTTP/1.1 500 Internal Server Error
Cache-Control: private
Date: Mon, 04 Jun 2012 15:54:47 GMT
Server: Microsoft-IIS/6.0
Content-Length: 441
Content-Type: text/xml; charset=utf-8
Client-Date: Mon, 04 Jun 2012 15:54:47 GMT
Client-Peer: 10.94.61.146:80
Client-Response-Num: 1
Set-Cookie: BIGipServer_____________-http=_________________; path=/
X-AspNet-Version: 2.0.50727
X-Powered-By: ASP.NET

<?xml version="1.0" encoding="utf-8"?><soap:Envelope xmlns:soap="http://schemas.
xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance
" xmlns:xsd="http://www.w3.org/2001/XMLSchema"><soap:Body><soap:Fault><faultcode
>soap:Server</faultcode><faultstring>Server was unable to process request. ---&g
t; Object reference not set to an instance of an object.</faultstring><detail />
</soap:Fault></soap:Body></soap:Envelope>
SOAP::Deserializer::deserialize: ()
SOAP::Parser::decode: ()
SOAP::SOM::new: ()
SOAP::Lite::DESTROY: ()
SOAP::Deserializer::DESTROY: ()
SOAP::Transport::DESTROY: ()
SOAP::Transport::HTTP::Client::DESTROY: ()
SOAP::Serializer::DESTROY: ()
SOAP::Data::DESTROY: ()
SOAP::Data::DESTROY: ()
SOAP::Data::DESTROY: ()
SOAP::Data::DESTROY: ()
SOAP::Data::DESTROY: ()
lets test it...

1
result():
SOAP::SOM::DESTROY: ()
SOAP::Data::DESTROY: ()
SOAP::Parser::DESTROY: ()
SOAP::Transport::DESTROY: ()
SOAP::Serializer::DESTROY: ()
SOAP::Deserializer::DESTROY: ()
SOAP::Lite::DESTROY: ()
Press any key to continue . . .

After some research I've done, I've got the impression that the error is on the WS server's side. Yet the WS seems to work perfectly, so I guess something is wrong with my Perl script but I cannot figure out what...

Any help would be very much appreciated !

Thanks,

[Update #1]

Here's the example given by the WS page:

Request

POST /zzzzz/directory.asmx HTTP/1.1
Host: yyyyy
Content-Type: text/xml; charset=utf-8
Content-Length: length
SOAPAction: "http://xxxxx/GetUIDFromNTLogin"

<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
  <soap:Body>
    <GetUIDFromNTLogin xmlns="http://xxxxx/">
      <NTLogin>string</NTLogin>
    </GetUIDFromNTLogin>
  </soap:Body>
</soap:Envelope>

Response

HTTP/1.1 200 OK
Content-Type: text/xml; charset=utf-8
Content-Length: length

<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
  <soap:Body>
    <GetUIDFromNTLoginResponse xmlns="http://xxxxx/">
      <GetUIDFromNTLoginResult>string</GetUIDFromNTLoginResult>
    </GetUIDFromNTLoginResponse>
  </soap:Body>
</soap:Envelope>

[Update #2]

Here's the output to what user1215106 suggested:

<HTML>
<HEAD><TITLE>An Error Occurred</TITLE></HEAD>
<BODY>
<H1>An Error Occurred</H1>
400 Bad Request
</BODY>
</HTML>
Will1v
  • 143
  • 2
  • 11
  • Anyone please? I'm really struggling with this... Thanks, – Will1v May 28 '12 at 11:58
  • I was trying to look through some old SOAP::Lite code where we authenticated via NT but couldn't find it. About the best I could do is add a bounty to get you a little more attention. It looks like it's a simple case of the HTTP Transport layer needing NT authentication--which LWP *can* do. Brittle server code in the .NET world often returns 'Object reference not set to an instance of an object.' – Axeman May 31 '12 at 11:51
  • I've seen the error myself when working with SOAP::WSDL quite often recently, but always had the guy on the other end fix the issues for me. So no real help here. :-/ – simbabque May 31 '12 at 12:13
  • Thanks a lot guys, especially for the bounty, it's really kind of you. I'll try and have a look at LWP to see if I can figure out anything. In the meanwhile, if anyone has any idea... Cheers – Will1v May 31 '12 at 14:17
  • The only thing different in my code is that I call result() before fault(). – aglassman May 31 '12 at 17:59
  • Actually, the fault method doesn't work. I just removed it and the result is exactly the same. @aglassman, I've added to my post the example given on the webservice page, do you spot any difference with your WS? I've got the impression I'm sending the right thing, but I might be missing something... Many thanks – Will1v Jun 01 '12 at 07:14
  • Sorry, Will, I *had* to award the bounty (less than an hour before the system automatically did it). I hope you get your answer eventually. Good luck. – Axeman Jun 07 '12 at 11:25
  • See if the analyses in this post helps you: http://stackoverflow.com/questions/5586145/client-of-web-service-in-perl/5586523#5586523 – Axeman Jun 07 '12 at 11:34
  • @Axeman you must be kidding! It was awfully nice of you to offer a bounty, I got lots of answers even if the question isn't solved yet. So thanks a lot, mate. I'll have a look at the other post you suggested. – Will1v Jun 07 '12 at 12:07

4 Answers4

3

Please test the code below and let us know your experience and output you got.

#!perl -w 

use strict; 
use warnings;
use LWP::UserAgent; 
use SOAP::Lite

use LWP::Debug; LWP::Debug::level('+'); SOAP::Lite->import(+trace => 'all');

print SOAP::Lite 
  -> uri('http://xxxxx') 
  -> proxy('http://yyyyy/zzzzz/directory.asmx') 
  -> on_action(sub { sprintf '"%s"', shift })
  -> on_fault(sub {
       my($soap, $res) = @_; 
       die ref $res ? $res->faultstring : $soap->transport->status, "\n";
     })
  -> GetUIDFromNTLogin(SOAP::Data->type('string')->name('NTLogin')->value(1234))
  -> result;

[UPDATE]

Based on information you posted, I suggest you to execute direct HTTP::Request code, without library SOAP::Lite. Modify the code below with exact information you have:

#!perl -w          

use strict;          
use warnings;

use LWP::UserAgent;
use HTTP::Request;

my $message = '<SOAP-ENV:Envelope xmlns:xsi="http://www.w3.org/1999/XMLSchema-instance" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/1999/XMLSchema" SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"><SOAP-ENV:Body><namesp1:GetUIDFromNTLogin xmlns:namesp1="http://tempuri.org"><NTLogin xsi:type="s:string">1234</NTLogin></namesp1: GetUIDFromNTLogin></SOAP-ENV:Body></SOAP-ENV:Envelope>';

my $userAgent = LWP::UserAgent->new();
my $request = HTTP::Request->new(POST => 'http://...');
$request->header(SOAPAction => '"http://tempuri.org/GetUIDFromNTLogin"');
$request->content($message);
$request->content_type("text/xml; charset=utf-8");

my $response = $userAgent->request($request);

if ($response->code == 200) {
  print $response->as_string;
}
else {
  print $response->error_as_HTML;
}
Ωmega
  • 42,614
  • 34
  • 134
  • 203
  • Hi, Thanks a lot for your answer, unfortunately, I get this error message again: Server did not recognize the value of HTTP Header SOAPAction: http://xxxxx By the way, http://xxxxx is http://tempuri.org, which is - I guess - the default address when you write a .Net WS. It's what I can see in the official example anyway, but maybe shouldn't I use this? – Will1v Jun 04 '12 at 06:58
  • OK, now I have a 400 return error code (400 Bad Request). It's a better, but there are two things I'm not sure about: First one is: the login isn't 1234, it's something with a back slash. Should I put my login between (simple/double/no) quotes? Should I put a \\ instead of a \. Or should I use an ASCII code (%5C)? And the second thing is, what should I put in 'new'? I tried the WSDL url, I also tried http://yyyyy/zzzzz//directory.asmx and http://yyyyy/zzzzz//directory.asmx?op=GetUIDFromNTLogin, I still get the same result. Thanks a lot for your help! – Will1v Jun 06 '12 at 16:59
  • I've added the output to my original question. – Will1v Jun 06 '12 at 17:10
  • 2
    @Will1v - Backslash is not special character in XML, so use it regulary. There are only 5 characters in XML that need to be escaped and those are: `"` ("), `'` ('), `<` (<), `>` (>) and `&` (&) – Ωmega Jun 06 '12 at 17:57
  • @Will1v - I believe there should be no double slash `//` in url and such url should be absolute `http://...`. The reason you are getting error 400 is that your url is not correct. – Ωmega Jun 06 '12 at 18:05
  • Oh the double slash is only a mistype in the comment, it was a single slash in the script. I'll try and figure out what is wrong with the url tomorrow... – Will1v Jun 06 '12 at 21:24
1

“Server was unable to process request. Object reference not set to an instance of an object”

After some research I've done, I've got the impression that the error is on the WS server's side. Yet the WS seems to work perfectly, so I guess something is wrong with my Perl script but I cannot figure out what...

This is definitely a server-side error. It is due to what's arguably a bug in the .NET server code. It's a System.NullReferenceException, easy to reproduce:

D:\temp :: more nr.cs
class Program {
        static void Main() {
                object o = null;
                string s = o.ToString();
        }
}

D:\temp :: csc /nologo nr.cs

D:\temp :: nr.exe

Unbehandelte Ausnahme: System.NullReferenceException:
Der Objektverweis wurde nicht auf eine Objektinstanz festgelegt.
   bei Program.Main()

This doesn't have anything to do with your SOAP client, only that the client exposes the bug by eliciting the error message.

In a comment on another reply your wrote:

By the way, xxxxx is tempuri.org, which is - I guess - the default address when you write a .Net WS. It's what I can see in the official example anyway, but maybe shouldn't I use this?

It's a wild guess, but a user in another discussion got a NullReferenceException because he didn't supply the correct URL for the SOAPAction header. This is something you could check. Find out what the SOAPAction header is supposed to be and make sure you set it accordingly. If you have access to what's happening server-sice that would help in debugging, of course, because ultimately the bug is clearly server-side.

Community
  • 1
  • 1
Lumi
  • 14,775
  • 8
  • 59
  • 92
  • Thanks a lot for your answer, @Lumi. tempuri.org is the uri I see in the example, it's also what I see in the WSDL ('targetNamespace' tag). Is there somewhere else I should check? – Will1v Jun 05 '12 at 07:36
  • And about the server-side bug, the WS does work when I use the official web page, with a form where you can provide the NT login. So there must be a way of making it work... I just can't figure out how... – Will1v Jun 05 '12 at 07:37
  • 1
    @Will1v - Sounds like you got the correct URI then. A service responding with a `NullReferenceException` arguably is buggy. The form submission simply doesn't evidentiate the bug. So the web form works? And it also invokes the web service? Then you should analyse the request generated by the form submission and reproduce it in your code. – Lumi Jun 05 '12 at 16:14
  • good idea, but how can I see what the web form sends? Something like wireshark? Or is there an easier solution? Thanks a lot for your help – Will1v Jun 05 '12 at 17:45
  • It's not clear from your description how exactly the web form calls the service. It could be REST style GET or POST instead of SOAP. It could also send the parameters to a server-side script that in turn calls the service. To analyze HTTP traffic in your browser, use Firebug or (better) HttpFox, or corresponding facilities of other browsers. To see actions taken server-side you obviously need server access. It's not clear from your description whether you have server access or not. If yes then use it to find out where the exception is occurring. – Lumi Jun 05 '12 at 18:14
  • No I don't have access at all. The WS is provided, I can only consume it. I'll try the HttpFox trick tomorrow then. Thanks – Will1v Jun 05 '12 at 19:07
1

We all agree that the HTTP 500 server error indicates an error on the server side.

So the first port of call is to retrieve full debugging logs from the WebService Application and send them off to the developer/vendor of that WebService. Report this as a bug in their implementation. Tolerate no nonsense here. Even if your Perl client is passing bad (or missing) data across to the Web Service they should not respond with HTTP 500 Server Error. That's a bug. The error message should put its' arms around the defective client request and give an error message that should read along the lines of, "Ah look here. What's this you're sending me? Didn't I tell you in my lovely documentation that the NTUser has to exist on the system? (or whatever the problem is) Send across that request again but this time send it to me with real data that I can use." The error should be in the HTTP 400 range.

If required, to further backup your case that this is a defect in the Web Service code eliminate your Perl client as being the root cause of the problem by reproducing the error using SOAPUi

You can then share the Soap UI project with the web service developers, it should help them easily find this bug.

Rob Kielty
  • 7,958
  • 8
  • 39
  • 51
  • Cheers, it might be a good idea to contact the devs. I only need to figure out they are... :) – Will1v Jun 06 '12 at 08:27
  • There's no might about it. Give us the WSDL, the event logs, and we'll tell you who they are. It's the single piece of info missing from the question that is making this impossible to answer. – Rob Kielty Jun 06 '12 at 09:00
0

I found this: http://www.perlmonks.org/?node_id=719987

The guy added this line to their code:

sub SOAP::Transport::HTTP::Client::get_basic_credentials { 
    return ('user' => 'password') 
};

Also, please use use strict; use warnings;

Move the shebang line at the top (#!perl)

Enable debug:

use LWP::UserAgent;
use LWP::Debug;
LWP::Debug::level('+');
SOAP::Lite->import(+trace => 'all');

Make sure that LWP::Authen::Ntlm is installed in your system.

Currently you are getting 'HTTP/1.1 500 Internal Server Error' errors. This means that the server code dies, does not work properly. It should send you some meaningfull error message...

Regards,

Lorenz Lo Sauer
  • 23,698
  • 16
  • 85
  • 87
user1126070
  • 5,059
  • 1
  • 16
  • 15
  • Thanks for your answer and sorry about the disgusting coding, I've cleaned it up a bit. I'm going to give a try at all this and let you know. Thanks again! – Will1v Jun 01 '12 at 10:14
  • No success either... In any case, the WS doesn't seem protected by credentials. – Will1v Jun 01 '12 at 14:36
  • I've updated the script and the output I get with the modifications you suggested. However, the tags in the output (which I suppose are sent to the server), are not exactly the same as the ones in the official example. For instance: – Will1v Jun 01 '12 at 16:08
  • And this return code "1" isn't very explicit... Do you have any other idea? Thanks a lot! – Will1v Jun 01 '12 at 16:11
  • I you added that trace settings it should output a lot of things. Please add that output to your question. – user1126070 Jun 04 '12 at 09:18
  • I just ran the script in my question (with the log level you suggested) again and copy/pasted the output in the original question, it is the same that the one I had previously. – Will1v Jun 04 '12 at 16:09