You need to sign in to do that
Don't have an account?
Help with Windows Phone connecting to Salesforce Enterprise API
Hi!
I am trying to call the Enterprise Web Service in Salesforce on my Dev org.
I have the login working correctly, but when I try to make the next call to retrieve I am getting an error.
I was using this great article as a reference:
http://www.developer.com/net/net/salesforce-integration-with-.net-web-services-soap-api-.html?comment=53310-5710
I am trying to do this on a Windows Phone Application through Microsoft Visual Studio 2010 Express for Windows Phone.
This means when I do the 'Add Service References' option and I specify my wsdl that I do not get a wrapper class for setting my metadata URL and the Session ID.
I think my problem is that I do not have my Session ID set in the header section of the Soap Request.
I think I have the metadata URL set properly in the new EndPointAddress that I created.
In Windows Phone I have to make all calls asynchronously, which then makes me specify a callback method.
Here is my endpoint in the Services.ClientConfig file for the initial login call:
<endpoint address="https://login.salesforce.com/services/Soap/c/21.0"
binding="basicHttpBinding" bindingConfiguration="SoapBinding1"
contract="SForceServiceE.Soap" name="SoapE" />
Here is the exception...
Message "No operation available for request {urn:enterprise.soap.sforce.com}retrieve" string
Stack Trace:
StackTrace " at System.ServiceModel.DiagnosticUtility.ExceptionUtility.BuildMessage(Exception x)\r\n at System.ServiceModel.DiagnosticUtility.ExceptionUtility.LogException(Exception x)\r\n at System.ServiceModel.DiagnosticUtility.ExceptionUtility.ThrowHelperWarning(Exception e)\r\n at System.ServiceModel.Channels.ServiceChannel.HandleReply(ProxyOperationRuntime operation, ProxyRpc& rpc)\r\n at System.ServiceModel.Channels.ServiceChannel.EndCall(String action, Object[] outs, IAsyncResult result)\r\n at System.ServiceModel.ClientBase`1.ChannelBase`1.EndInvoke(String methodName, Object[] args, IAsyncResult result)\r\n at YouTubeSearch.SForceServiceE.SoapClient.SoapClientChannel.Endretrieve(IAsyncResult result)\r\n at YouTubeSearch.SForceServiceE.SoapClient.YouTubeSearch.SForceServiceE.Soap.Endretrieve(IAsyncResult result)\r\n at YouTubeSearch.SForceServiceE.SoapClient.Endretrieve(IAsyncResult result)\r\n at YouTubeSearch.SForceServiceE.SoapClient.OnEndretrieve(IAsyncResult result)\r\n at System.ServiceModel.ClientBase`1.OnAsyncCallCompleted(IAsyncResult result)\r\n at System.ServiceModel.AsyncResult.Complete(Boolean completedSynchronously)\r\n at System.ServiceModel.AsyncResult.Complete(Boolean completedSynchronously, Exception exception)\r\n at System.ServiceModel.Channels.ServiceChannel.SendAsyncResult.CallComplete(Boolean completedSynchronously, Exception exception)\r\n at System.ServiceModel.Channels.ServiceChannel.SendAsyncResult.FinishSend(IAsyncResult result, Boolean completedSynchronously)\r\n at System.ServiceModel.Channels.ServiceChannel.SendAsyncResult.SendCallback(IAsyncResult result)\r\n at System.ServiceModel.AsyncResult.Complete(Boolean completedSynchronously)\r\n at System.ServiceModel.AsyncResult.Complete(Boolean completedSynchronously, Exception exception)\r\n at System.ServiceModel.Channels.HttpChannelFactory.HttpRequestChannel.HttpChannelAsyncRequest.OnGetResponse(IAsyncResult result)\r\n at System.Net.Browser.ClientHttpWebRequest.<>c__DisplayClassa.<InvokeGetResponseCallback>b__8(Object state2)\r\n at System.Threading.ThreadPool.WorkItem.doWork(Object o)\r\n at System.Threading.Timer.ring()\r\n" string
Here is the Soap Request...
Request {<?xml version="1.0" encoding="utf-16"?>
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
<s:Header />
<s:Body xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<retrieve xmlns="urn:enterprise.soap.sforce.com">
<fieldList>Name</fieldList>
<sObjectType>Game__c</sObjectType>
<ids>
<string>a00E0000000iaEcIAI</string>
</ids>
</retrieve>
</s:Body>
</s:Envelope>} System.ServiceModel.Channels.Message {System.ServiceModel.Dispatcher.OperationFormatter.OperationFormatterMessage}
Here is the Soap Reply...
Reply {<?xml version="1.0" encoding="utf-16"?>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
<s:Header xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" />
<soapenv:Body>
<soapenv:Fault>
<faultcode>soapenv:Client</faultcode>
<faultstring>No operation available for request {urn:enterprise.soap.sforce.com}retrieve</faultstring>
</soapenv:Fault>
</soapenv:Body>
</soapenv:Envelope>} System.ServiceModel.Channels.Message {System.ServiceModel.Channels.BufferedMessage}
Here is the code I am using...
private void BuildClassFromSalesForce2()
{
SForceServiceE.SoapClient myClientR = new SForceServiceE.SoapClient("SoapE");
myClientR.loginAsync("MyEmail", "MyPasswordMySecurityToken");
myClientR.loginCompleted += new EventHandler<SForceServiceE.loginCompletedEventArgs>(soapLoginCompleted2);
}
private void soapLoginCompleted2(object src, SForceServiceE.loginCompletedEventArgs myArg)
{
var elements = new List<System.ServiceModel.Channels.BindingElement>();
elements.Add(new System.ServiceModel.Channels.TextMessageEncodingBindingElement(
System.ServiceModel.Channels.MessageVersion.Soap11, System.Text.Encoding.UTF8));
elements.Add(new System.ServiceModel.Channels.HttpsTransportBindingElement());
System.ServiceModel.Channels.CustomBinding myBinding = new System.ServiceModel.Channels.CustomBinding(elements);
System.ServiceModel.EndpointAddress myEndPoint = new System.ServiceModel.EndpointAddress(myArg.Result.metadataServerUrl);
//Where do I set myArg.Result.sessionId?
//doesn't this need to get into a session header in the Request SOAP message like this? How do I do this?
//<soapenv:Header>
// <urn:SessionHeader>
// <urn:sessionId>xxxxxx</urn:sessionId>
// </urn:SessionHeader>
//</soapenv:Header>
SForceServiceE.SoapClient myRetrieveClient = new SForceServiceE.SoapClient(myBinding, myEndPoint);
myRetrieveClient.retrieveCompleted += new EventHandler<SForceServiceE.retrieveCompletedEventArgs>(soapRetrieveCompleted2);
string[] ids = new string[1];
ids[0] = "a00E0000000iaEcIAI";
myRetrieveClient.retrieveAsync("Name", "Game__c", ids, myArg.UserState);
}
private void soapRetrieveCompleted2(object src, SForceServiceE.retrieveCompletedEventArgs myArg)
{
//It never gets to here. It errors out in SForceServiceE.retrieveResponse
MessageBox.Show("Retrieve Completed! Count: " + myArg.Result.Length);
}
Here is where it is erroring out:
public YouTubeSearch.SForceServiceE.retrieveResponse Endretrieve(System.IAsyncResult result) {
object[] _args = new object[0];
//Error here!
YouTubeSearch.SForceServiceE.retrieveResponse _result = ((YouTubeSearch.SForceServiceE.retrieveResponse)(base.EndInvoke("retrieve", _args, result)));
return _result;
}
What am I doing wrong?
One of the articles said this error is causing by referencing the Enterprise wsdl, but calling the partner API. Am I doing this?
Thanks!
Its not the namespace in retreive (which is correct), its this part
<ids>
<string>a00E0000000iaEcIAI</string>
</ids>
it should be
<ids>a00E0000000iaEcIAI</ids>
Have you thought of using the REST API instead ?
All Answers
What URL are you sending the request to ?
Simon,
Here is the value of myArg.Result.metadataServerUrl that I use when creating the Request object after the Login is complete.
"https://na9-api.salesforce.com/services/Soap/m/21.0/00DE0000000Hjbh"
System.ServiceModel.EndpointAddress myEndPoint = new System.ServiceModel.EndpointAddress(myArg.Result.metadataServerUrl);
Is that the URL you wanted to see?
Thanks!
Terry Luschen
Yes, that's the wrong url, you should be using Result.serverUrl
Thanks! I think I am farther now with serverUrl instead of metadataServerUrl.
I am now getting this error
Invalid Session ID found in SessionHeader: Illegal Session
I think this brings me back a question in my original post.
Where do I set myArg.Result.sessionId?
Doesn't this need to get into a session header in the Request SOAP message like this? How do I do this? This is very much a c# .net question I know.
Here is the SOAP response
+ Reply {<?xml version="1.0" encoding="utf-16"?>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:sf="urn:fault.enterprise.soap.sforce.com" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<s:Header xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" />
<soapenv:Body>
<soapenv:Fault>
<faultcode>sf:INVALID_SESSION_ID</faultcode>
<faultstring>INVALID_SESSION_ID: Invalid Session ID found in SessionHeader: Illegal Session</faultstring>
<detail>
<sf:UnexpectedErrorFault xsi:type="sf:UnexpectedErrorFault">
<sf:exceptionCode>INVALID_SESSION_ID</sf:exceptionCode>
<sf:exceptionMessage>Invalid Session ID found in SessionHeader: Illegal Session</sf:exceptionMessage>
</sf:UnexpectedErrorFault>
</detail>
</soapenv:Fault>
</soapenv:Body>
</soapenv:Envelope>} System.ServiceModel.Channels.Message {System.ServiceModel.Channels.BufferedMessage}
Thanks!
Terry
After adding in a Soap header with the SessionID I am still getting a message that: INVALID_SESSION_ID: Invalid Session ID found in SessionHeader: Illegal Session
I was able to add to add the message header for sessionID with code like this...
System.ServiceModel.Channels.AddressHeader addressHeader1 =
System.ServiceModel.Channels.AddressHeader.CreateAddressHeader( "sessionId", "", myArg.Result.sessionId);
System.ServiceModel.Channels.AddressHeader[] addressHeaders1 = new System.ServiceModel.Channels.AddressHeader[1] { addressHeader1};
Uri myUri = new Uri(myArg.Result.serverUrl);
System.ServiceModel.EndpointAddress myEndPoint = new System.ServiceModel.EndpointAddress(myUri, addressHeaders1);
Here is my Request....
- Request {<?xml version="1.0" encoding="utf-16"?>
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
<s:Header>
<sessionId>00DE0000000Hjbh!ARkAQJQX2UtqFTZKP24r7PTthlu6vwZR7JWJn5YLoRNKYAimRLZTNtIzrkwNzAabQgjkIeMkKf.mFbmsNDuZJJoiBvugyPYu</sessionId>
</s:Header>
<s:Body xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<retrieve xmlns="urn:enterprise.soap.sforce.com">
<fieldList>Name</fieldList>
<sObjectType>Game__c</sObjectType>
<ids>
<string>a00E0000000iaEcIAI</string>
</ids>
</retrieve>
</s:Body>
</s:Envelope>} System.ServiceModel.Channels.Message {System.ServiceModel.Dispatcher.OperationFormatter.OperationFormatterMessage}
Here is the reply with the error...
+ Reply {<?xml version="1.0" encoding="utf-16"?>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:sf="urn:fault.enterprise.soap.sforce.com" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<s:Header xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" />
<soapenv:Body>
<soapenv:Fault>
<faultcode>sf:INVALID_SESSION_ID</faultcode>
<faultstring>INVALID_SESSION_ID: Invalid Session ID found in SessionHeader: Illegal Session</faultstring>
<detail>
<sf:UnexpectedErrorFault xsi:type="sf:UnexpectedErrorFault">
<sf:exceptionCode>INVALID_SESSION_ID</sf:exceptionCode>
<sf:exceptionMessage>Invalid Session ID found in SessionHeader: Illegal Session</sf:exceptionMessage>
</sf:UnexpectedErrorFault>
</detail>
</soapenv:Fault>
</soapenv:Body>
</soapenv:Envelope>} System.ServiceModel.Channels.Message {System.ServiceModel.Channels.BufferedMessage}
Help? Is my SessionID not formatted properly?
Does it have to look like this instead?
//<soapenv:Header>
// <urn:SessionHeader>
// <urn:sessionId>xxxxxx</urn:sessionId>
// </urn:SessionHeader>
Thanks!
Yes, your session header is wrong, and it should be as you state at the end of the post.
I really appreciate your help Simon!
I can now make my request look a lot better by formatting an object instead of a string, but I stil get the same 'Invalid Session ID' error.
Here is my new code:
SessionHeader myHeader = new SessionHeader();
myHeader.sessionId = myArg.Result.sessionId;
System.ServiceModel.Channels.AddressHeader addressHeader1 =
System.ServiceModel.Channels.AddressHeader.CreateAddressHeader("SessionHeader", "", myHeader);
Here is my new request object:
+ Request {<?xml version="1.0" encoding="utf-16"?>
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
<s:Header>
<SessionHeader xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<sessionId xmlns="http://schemas.datacontract.org/2004/07/YouTubeSearch">00DE0000000Hjbh!ARkAQNp45M8a5FG3x.SoookJIuDbIxQzUcFECgbJ8MFsa3ZaU417HQXHWtWYNrtoDjhbP9qojWDwxpQ45Zon.L4_Xw1FHTd7</sessionId>
</SessionHeader>
</s:Header>
<s:Body xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<retrieve xmlns="urn:enterprise.soap.sforce.com">
<fieldList>Name</fieldList>
<sObjectType>Game__c</sObjectType>
<ids>
<string>a00E0000000iaEcIAI</string>
</ids>
</retrieve>
</s:Body>
</s:Envelope>} System.ServiceModel.Channels.Message {System.ServiceModel.Dispatcher.OperationFormatter.OperationFormatterMessage}
Do I have to some how get the urn: in front of the SessionHeader and SessionId values?
Is the "xmlns" causing a problem?
Thanks!
Terry
The SessionHeader and sessionId elements are both in the wrong namespace, the exact prefix doesn't matter, but the URI does, it needs to look something like
or
I have been able to manipulate the SessionHeader xmlns values with the DataContract and DataMember values from System.Runtime.Serialization.
I'm sorry to say this, but..
Here is my new error:
<faultcode>soapenv:Client</faultcode>
<faultstring>Unexpected element {urn:enterprise.soap.sforce.com}string during simple type deserialization</faultstring>
I'm pretty sure this error is referring to the "urn:enterprise.." after the <retrieve.
I can tell this because if I change the urn:enterprise in the SessionHeader line to something random I still
get the same error.
My Request:
+ Request {<?xml version="1.0" encoding="utf-16"?>
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
<s:Header>
<SessionHeader xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="urn:enterprise.soap.sforce.com">
<sessionId xmlns="">00DE0000000Hjbh!ARkAQB6ICOrIIDensjf47Ek2KMngWY0OUeVLB0CKYpPU.AToXLPw_5ZTA6gWCuCLhpMi5uBbvY7.QPk4tAHxw00bZyhmNG2s</sessionId>
</SessionHeader>
</s:Header>
<s:Body xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<retrieve xmlns="urn:enterprise.soap.sforce.com">
<fieldList>Name</fieldList>
<sObjectType>Game__c</sObjectType>
<ids>
<string>a00E0000000iaEcIAI</string>
</ids>
</retrieve>
</s:Body>
</s:Envelope>} System.ServiceModel.Channels.Message {System.ServiceModel.Dispatcher.OperationFormatter.OperationFormatterMessage}
My Reply:
+ Reply {<?xml version="1.0" encoding="utf-16"?>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
<s:Header xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" />
<soapenv:Body>
<soapenv:Fault>
<faultcode>soapenv:Client</faultcode>
<faultstring>Unexpected element {urn:enterprise.soap.sforce.com}string during simple type deserialization</faultstring>
</soapenv:Fault>
</soapenv:Body>
</soapenv:Envelope>} System.ServiceModel.Channels.Message {System.ServiceModel.Channels.BufferedMessage}
I hope somebody else will learn from my pain. :)
Thanks Again!
Terry Luschen
Its not the namespace in retreive (which is correct), its this part
<ids>
<string>a00E0000000iaEcIAI</string>
</ids>
it should be
<ids>a00E0000000iaEcIAI</ids>
Have you thought of using the REST API instead ?
Simon,
I ( we ) got it!
Thank you for all your help!! I have learned a ton.
I switched to using the queryAsync to work around the problem with the <ids> not being on the same line. If the 'MessageHeaderArrayAttribute' were available in the Windows Phone .NET environment I would have been able to make it work. But anyway, it works now!
string qry;
qry = @"SELECT ID, Name, Phone, Email, Department FROM User";
myRetrieveClient.queryCompleted += new EventHandler<SForceServiceE.queryCompletedEventArgs>(soapQueryCompleted2);
myRetrieveClient.queryAsync(qry, myArg.UserState);
Thanks!
Terry Luschen
Can you please tell me How did you add salesforce API in windows phone. I am working on this and I am unable to even add this.
Thanks