WSMakeStubs/WSGenerateObj findings calling ASP.NET webservice
WSMakeStubs/WSGenerateObj findings calling ASP.NET webservice
- Subject: WSMakeStubs/WSGenerateObj findings calling ASP.NET webservice
- From: "Mike Cahill" <email@hidden>
- Date: Sat, 20 Aug 2005 14:13:12 -0700
- Thread-topic: WSMakeStubs/WSGenerateObj findings calling ASP.NET webservice
Hi
Thought I'd collect what I have learned in the last couple of weeks
about calling an ASP.NET web service from Cocoa all in one place. I'm a
Cocoa newbie so maybe someone can correct me if I have misunderstood
anything. Some of this information is scattered about and the last
couple of items I haven't seen mentioned anywhere.
To set this up, I have an ASP.NET webservice written in C# with the
default namespace of tempuri.org and I have Cocoa stubs generated by
WSMakeStubs.
Problem 1 - failure to call asp.net webservice
I had to make a couple of changes to make this work - both documented in
other places. First of all, the soapAction and methodNamespace were
missing in the generated stub file. Also, the kWSSOAPBodyEncodingStyle
value was wrong:-
Original code:
- (WSMethodInvocationRef) genCreateInvocationRef {
return [self createInvocationRef
/*endpoint*/:@"http://172.16.1.108/MyWebService/Service1.asmx"
methodName: @"DoSomething"
protocol: (NSString*) kWSSOAP2001Protocol
// missing encoding style - defaulting to RPC
style: (NSString*) kWSSOAPStyleRPC
soapAction: nil /* No SOAPAction header needed */
methodNamespace: NULL /* No Method Namespace specified */
];
}
Modified code:
- (WSMethodInvocationRef) genCreateInvocationRef {
return [self createInvocationRef
/*endpoint*/:@"http://172.16.1.108/MyWebService/Service1.asmx"
methodName: @"DoSomething"
protocol: (NSString*) kWSSOAP2001Protocol
style: (NSString*) kWSSOAPStyleDoc // CHANGED
soapAction: @"http://tempuri.org/DoSomething" // CHANGED
methodNamespace: @"http://tempuri.org/" // CHANGED important - don't
forget the trailing forward slash
];
}
Also, .NET requires a SOAP action so the WSGeneratedObj.m file needs to
be modified to work correctly. The name of the locally declared variable
'soapAction' conflicts with the parameter passed in with the same name:
Original code:
NSString* soapAction = @"SOAPAction";
NSDictionary* headers = [self copyHeaderDictionary:1
extraVals:&soapAction extraKeys:&soapAction];
Modified code:
NSString* soapActionKey = @"SOAPAction";
NSDictionary* headers = [self copyHeaderDictionary:1
extraVals:&soapAction extraKeys:&soapActionKey];
At this stage, I can call my ASP.NET web service and retrieve a result
as expected.
Problem 2 - each web service call results in a memory leak
This took a while to find but it turns out the WSGeneratedObj dealloc
never gets called because its retain count doesn't reach 0. The reason
for this is that the WSMethodInvocationSetCallBack call towards the end
of the createInvocationRef method in WSGeneratedObj increments the
retain count. This method sets the callback for the asynchronous web
service call. The documentation for this method states that you should
call the method again passing in NULL for the second and third
parameters to clear the invocation. I added this extra call at the end
of getResultDictionary in WSGenenratedObj to decrement the retain
count:-
if(fRef) { // new code
WSMethodInvocationSetCallBack(fRef, NULL, NULL); // new code
} // new code
return fResult; // original code
Now the dealloc is called correctly when the invocation object is
released in the generated stub.
Problem 3 - application crashes now dealloc is called
Now dealloc is called and the object various objects are released
correctly, but I get a crash in NSPopAutoreleasePool indicating that an
object is being over-released somewhere. I tracked this down to (I
think) the extra release of the NSUrl in createInvocationRef in
WSGeneratedObj. It is my understanding that this returns an autoreleased
object:-
NSURL* url = [NSURL URLWithString: endpoint];
if (url == NULL) {
[self handleError: @"NSURL URLWithString failed in
createInvocationRef" errorString:NULL
errorDomain:kCFStreamErrorDomainMacOSStatus errorNumber:
paramErr];
} else {
ref = WSMethodInvocationCreate((CFURLRef) url, (CFStringRef)
methodName, (CFStringRef) protocol);
// [url release]; remove this line
....
And that's it. I can now call my ASP.NET web service correctly with no
leaks and no crashes. Please let me know if I have misunderstood any of
this and if not, I hope this helps the next person.
Cheers
Mike
_______________________________________________
Do not post admin requests to the list. They will be ignored.
Cocoa-dev mailing list (email@hidden)
Help/Unsubscribe/Update your Subscription:
This email sent to email@hidden