Unable to track changers with sync-collection operation of Google CardDAV API - google-api

I'm trying to use the sync-collection operation of Google CardDAV API. It's not well explained in the documentation. But I think following is what they have explained in this documentation.
First, discover the sync-token from address book using propfind operation. Following is my request and I get the sync-token successfully.
Request
Depth: 0
Content-Type: application/xml; charset=utf-8
<d:propfind xmlns:d="DAV:" xmlns:cs="http://calendarserver.org/ns/">
<d:prop>
<d:displayname />
<cs:getctag />
<d:sync-token />
</d:prop>
</d:propfind>
Response
ncoding="UTF-8"?>
<d:multistatus xmlns:cal="urn:ietf:params:xml:ns:caldav" xmlns:card="urn:ietf:params:xml:ns:carddav" xmlns:cs="http://calendarserver.org/ns/" xmlns:d="DAV:" xmlns:ical="http://apple.com/ns/ical/">
<d:response>
<d:href>/carddav/v1/principals/some#email.com/lists/default/</d:href>
<d:propstat>
<d:status>HTTP/1.1 200 OK</d:status>
<d:prop>
<d:displayname>Address Book</d:displayname>
<d:sync-token>https://www.googleapis.com/carddav/v1/synctoken/SOMEIDINHERE</d:sync-token>
<cs:getctag>"23fq3fqefas.8"</cs:getctag>
</d:prop>
</d:propstat>
</d:response>
</d:multistatus>
Then we have to do a sync-collection operation with sync-token to get changes from the previous state, but that doesn't return any item, regardless of whatever the change I do in my contact list at https://contacts.google.com/.
Request
<?xml version="1.0" encoding="utf-8" ?>
<d:sync-collection xmlns:d="DAV:" xmlns:C="urn:ietf:params:xml:ns:carddav">
<d:sync-token>https://www.googleapis.com/carddav/v1/synctoken/SOMEIDINHERE</d:sync-token>
<d:sync-level>1</d:sync-level>
<d:prop>
<d:displayname />
<d:current-user-principal />
<d:principal-URL/>
</d:prop>
</d:sync-collection>
Response
<?xml version="1.0" encoding="UTF-8"?>
<d:multistatus xmlns:cal="urn:ietf:params:xml:ns:caldav" xmlns:card="urn:ietf:params:xml:ns:carddav" xmlns:cs="http://calendarserver.org/ns/" xmlns:d="DAV:" xmlns:ical="http://apple.com/ns/ical/">
<d:sync-token>https://www.googleapis.com/carddav/v1/synctoken/SOMEIDINHERE </d:sync-token>
</d:multistatus>
Please let me know what am I doing wrong.

In general, the normal mode of operation is to issue a first sync-collection with an empty sync-token (see https://www.rfc-editor.org/rfc/rfc6578#section-3.8 ) and use the sync-token returned in the response in following requests.

Related

Filenet GetContent webservice returns the file incomplete

I am using Filenet 5.2.1 soap webservice GetContent :
http://myserver:9080/wsi/FNCEWS40MTOM.wsdl
and when trying to get content for a file that is larger than 1 MB, the returned response when read as base64 is only for part of the file not the whole file.
my request is as follows :
<soapenv:Envelope xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<soapenv:Header>
<Security xmlns="http://schemas.xmlsoap.org/ws/2002/12/secext">
<hd:UsernameToken xmlns:hd="http://schemas.xmlsoap.org/ws/2002/12/secext">
<hd:Username>myusername</hd:Username>
<hd:Password>mypassword</hd:Password>
</hd:UsernameToken>
</Security>
</soapenv:Header>
<soapenv:Body>
<p857:GetContentRequest validateOnly="0" xmlns:p857="http://www.filenet.com/ns/fnce/2006/11/ws/schema">
<p857:ContentRequest cacheAllowed="1" id="1" startOffset="0">
<p857:SourceSpecification classId="Document" itemIndex="0" objectId="{E408981D-FF67-4D91-B7A9-CEBEC4630AB0}" objectStore="myobjectstore"
serializationDuplicate="0" xsi:type="p857:ObjectSpecification"/>
<p857:ElementSpecification elementSequenceNumber="0" itemIndex="0"/>
</p857:ContentRequest>
</p857:GetContentRequest>
</soapenv:Body>
</soapenv:Envelope>
Response :
--A-B--MIME-BOUNDARY--27d99311536fa8c4-18606176189--Y-Z
Content-Transfer-Encoding: binary
Content-Type: application/xop+xml; type="application/soap+xml"; charset=UTF-8
Content-ID:
<v0-27d99311536fa8c4-18606176189#mtom.p8ce.filenet.com>
<?xml version="1.0" encoding="UTF-8"?>
<e:Envelope xmlns:d="http://www.w3.org/2001/XMLSchema" xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns:fn35="http://www.filenet.com/ns/fnce/2005/02/ws/schema" xmlns:fn40m="http://www.filenet.com/ns/fnce/2006/11/ws/MTOM/schema" xmlns:fn40="http://www.filenet.com/ns/fnce/2006/11/ws/schema" xmlns:xop="http://www.w3.org/2004/08/xop/include" xmlns:e="http://schemas.xmlsoap.org/soap/envelope/">
<e:Body>
<GetContentResponse xmlns="http://www.filenet.com/ns/fnce/2006/11/ws/schema">
<ContentResponse id="1" i:type="fn40:ContentElementResponse" retrievalName="test.pdf" totalSize="4586622" bufferedSize="1048576" continueFrom="offset=1048576;id={B3795692-DA06-468C-AEC9-523A3715455D};">
<SourceSpecification i:type="fn40:ObjectReference" classId="Document" objectId="{E408981D-FF67-4D91-B7A9-CEBEC4630AB0}" objectStore="MCIDEV"></SourceSpecification>
<ElementSpecification elementSequenceNumber="0"></ElementSpecification>
<Content i:type="fn40:InlineContent">
<Binary>
<xop:Include href="cid:v1-27d99311536fa8c4-18606176189#mtom.p8ce.filenet.com"></xop:Include>
</Binary>
</Content>
</ContentResponse>
</GetContentResponse>
</e:Body>
</e:Envelope>
--A-B--MIME-BOUNDARY--27d99311536fa8c4-18606176189--Y-Z
Content-Transfer-Encoding: binary
Content-Type: application/octet-stream
Content-Id:
<v1-27d99311536fa8c4-18606176189#mtom.p8ce.filenet.com>
%PDF-1.4
......
......
......
--A-B--MIME-BOUNDARY--27d99311536fa8c4-18606176189--Y-Z--
The problem was in filenet configuration :
Inline Content Retrieval Limit default is 1 MB so that filenet webservice itself was returning 1 MB only of the file.
Increasing the value fixed the issue, but unfortunately the maximum is 10 MB.
https://www.ibm.com/docs/en/filenet-p8-platform/5.5.x?topic=engine-improving-content-uploads-downloads

Filtering with Quickbooks Online V2 returns 401 ErrorCode=003200, Empty body posts work perfectly

We're attempting to integrate with the QuickBooks Online V2 api using Ruby 1.9.3 (not RoR).
Using the API Explorer and the Employee endpoint documentation we were able to get a simple list of test employees by using the Google Signet OAuth Gem.
require 'signet'
require 'signet/oauth_1/client'
#intialize oauth1 client
#client = Signet::OAuth1::Client.new(
:temporary_credential_uri => "https://oauth.intuit.com/oauth/v1/get_request_token",
:authorization_uri => "https://appcenter.intuit.com/Connect/Begin",
:token_credential_uri => "https://oauth.intuit.com/oauth/v1/get_access_token",
:client_credential_key => 'qyprdPEfJqU7eOze0Fby9iYhrUS5DQ',
:client_credential_secret => 'fuXsasJo4TrTEd3Yhv4TeMUizmtguh0JioIB5r2I',
:callback => "http://localhost:3000/callback/general"
)
#client.token_credential_key = 'qyprdJUtDSk7owxVfZlq7JeWO1mtpHBkSMD5GhB02PwIC6N0'
#client.token_credential_secret = 'Rq2ekgQWWL9frZAKpcgWef291mR0J5HBE354u5F3'
#setup request
original_request = [
'POST',
'https://qbo.sbfinance.intuit.com/resource/employees/v2/791630875',
# we also tried this url 'https://qbo.intuit.com/qbo28/resource/employees/v2/791630875',
[
['Content-Type', 'application/x-www-form-urlencoded'],
],
[]
]
#execute request
response = #client.fetch_protected_resource(:request => original_request)
puts response.body
As you can see the request is pretty straight-forward.
However once we create a request with a Filter in the body, we get an HTML page with the following error: HTTP Status 401 - message=Exception authenticating OAuth; errorCode=003200; statusCode=401
#setup request
original_request = [
'POST',
'https://qbo.intuit.com/qbo28/resource/employees/v2/791630875',
#'https://qbo.sbfinance.intuit.com/resource/employees/v2/791630875',
[
['Content-Type', 'application/x-www-form-urlencoded'],
],
["Filter=Name :EQUALS: Doe"]
]
We're using the Google OAuth gem, and I've verified the signature generation to be correct using these tools: LinkedIn Oauth Test Console and Beginners guide to OAuth signing requests. They both verify that the signature that Signet is generating is correct for the body I provide.
I've looked at a few SO Questions:
QuickBooks Online querying with filter returns 401 everytime
Unable to create(POST) objects (Account, customer...) on QB Windows using IDS and Sync Manager
But nothing has worked. Any help would be appreciated, we're willing to use a third party gem such as quickeebooks but we would rather not. I assume I'm just missing something simple here.
Please provide me with the following items so I can verify a working answer:
Your request parameters, including uri, header, body and exact client and access tokens (developer app tokens only please, I'll need to verify that I can generate the exact same request, including signature)
You basestring used for generating the HMAC-SHA1 signature. it will look something like
POST&https%3A%2F%2Fqbo.intuit.com%2Fqbo28%2Fresource%2Femployees%2Fv2%2F7916308‌​75&Filter%3DName%2520%253AEQUALS%253A%2520David%2520Test%26oauth_consumer_key%3Dq‌​yprdPEfJqU7eOze0Fby9iYhrUS5DQ%26oauth_nonce%3D-1787433535548338293%26oauth_signat‌​ure_method%3DHMAC-SHA1%26oauth_timestamp%3D1380089100%26oauth_token%3DqyprdJUtDSk‌​7owxVfZlq7JeWO1mtpHBkSMD5GhB02PwIC6N0%26oauth_version%3D1.0
Your response, including header and body data
I had tried to use filter query with employee endpoint. It works fine.
EDIT - Sharing endpoint, filter and resultset related to Employee API Endpoint
https://qbo.intuit.com/qbo28/resource/employees/v2/791926875
Filter= Name :EQUALS: Manas Mukherjee
header - "Authorization: OAuth oauth_token="2eRrd7LhEtHrM1CrqWvy1kmSgeukEgFxW99E1xwhSsLCp1JB", oauth_consumer_key="qyprdXsaKh0a132eNs7NTJLufjfrzm", oauth_version="1.0", oauth_signature_method="HMAC-SHA1", oauth_timestamp="1380084612", oauth_nonce="1556081845430558974", oauth_signature="IMjh%2FTx%2F7GMFDE6WQqZK8b6apjI%3D"[\r][\n]"
Content-Type: application/x-www-form-urlencoded
Data Set
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<qbo:SearchResults xmlns="http://www.intuit.com/sb/cdm/v2" xmlns:qbp="http://www.intuit.com/sb/cdm/qbopayroll/v1" xmlns:qbo="http://www.intuit.com/sb/cdm/qbo">
<qbo:CdmCollections xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="Employees">
<Employee>
<Id idDomain="QBO">20</Id>
<SyncToken>0</SyncToken>
<MetaData>
<CreateTime>2013-09-24T21:37:22-07:00</CreateTime>
<LastUpdatedTime>2013-09-24T21:37:22-07:00</LastUpdatedTime>
</MetaData>
<Name>Manas Mukherjee</Name>
<Address>
<Line1>ABC Str</Line1>
<City>London</City>
<PostalCode>4353543</PostalCode>
<GeoCode>LAT=51.5148382,LNG=-0.1264144</GeoCode>
</Address>
<GivenName>Manas</GivenName>
<MiddleName>Kr</MiddleName>
<FamilyName>Mukherjee</FamilyName>
<ShowAs>Manas Kr Mukherjee</ShowAs>
<BillableTime>false</BillableTime>
</Employee>
</qbo:CdmCollections>
<qbo:Count>1</qbo:Count>
<qbo:CurrentPage>1</qbo:CurrentPage>
</qbo:SearchResults>
OAuth header using your tokens
"Authorization: OAuth oauth_token="qyprdJUtDSk7owxVfZlq7JeWO1mtpHBkSMD5GhB02PwIC6N0", oauth_consumer_key="qyprdPEfJqU7eOze0Fby9iYhrUS5DQ", oauth_version="1.0", oauth_signature_method="HMAC-SHA1", oauth_timestamp="1380089100", oauth_nonce="-1787433535548338293", oauth_signature="Vj67xMVhSKGjVSmGyOxt7SVv0i8%3D"[\r][\n]"
Endpoint - https://qbo.intuit.com/qbo28/resource/employees/v2/791630875
Post data to end point: Filter= Name :EQUALS: David Test
Content-Type: application/x-www-form-urlencoded
It works fine
Thanks
See this sample fiddler request with Filter for items in QBO. I cannot paste the fiddler log here. You can do it for similarly for Employee. The filters should go into the body and encode your header:
Request-
POST https://qbo.intuit.com/qbo1/resource/items/v2/723488155
HTTP/1.1
Content-Type: application/x-www-form-urlencoded
Authorization: OAuth oauth_token="lvprdgF9q4mSQx5A6lKNm3NISXvwIpF16z",oauth_nonce="3740352e-20a4-4d45-af4f-2b783ee20e60",oauth_consumer_key="qyprd7I5WvVnPoiBh1ejZn",oauth_signature_method="HMAC-SHA1",oauth_timestamp="1377106651",oauth_version="1.0",oauth_signature="1OAJXk5uH0sEpYpdhh%2BDMzjQFEs%3D"
Host: qbo.intuit.com
Content-Length: 28
Expect: 100-continue
PageNum=1&ResultsPerPage=100
Response Header-
HTTP/1.1 200 OK
Date: Wed, 21 Aug 2013 17:37:31 GMT
Server: Apache
Set-Cookie: qboeuid=10.129.32.5.1377106651774076; path=/; expires=Thu, 21-Aug-14 17:37:31 GMT; domain=.intuit.com
Set-Cookie: JSESSIONID=82DE11473B5246497B9FDCD8A6DA4C45.c1-pprdqboas30j; Path=/; Secure; HttpOnly
Vary: Accept-Encoding
Content-Type: application/xml;charset=UTF-8
Content-Length: 32525

Arduino POST ERROR bad Request-Line `'

I am making a web application to host JSON data POSTed from an Arduino to be hashed and stored in a database.
I am having an issue with the POST request to the web app being sent from the Arduino but I can't put my finger on it.
The error being received:
[28/Sep/2013:15:43:01 CDT] "POST /json HTTP/1.1" 200 0
- -> /json
[2013-09-28 15:43:06] ERROR bad Request-Line `'.
[28/Sep/2013:15:43:06 CDT] "" 400 0
The Arduino POST:
if (client.connect(server, 4567)) {
Serial.println("connected");
// Make a HTTP request:
client.println("POST /json HTTP/1.1");
client.println("User-Agent: Arduino");
client.println("Host: localhost:4567");
client.print("Accept: *"); client.print("/"); client.println("*");
client.println("Content-Length: 15");
client.println("Content-Type: application/x-www-form-urlencoded");
client.println("");
client.println("{\"plot\":\"85.1\"}");
client.println("");
}
I am using Ruby with Sinatra for the web app.
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN">
<HTML>
<HEAD><TITLE>Bad Request</TITLE></HEAD>
<BODY>
<H1>Bad Request</H1>
bad Request-Line `'.
<HR>
<ADDRESS>
WEBrick/1.3.1 (Ruby/1.9.3/2013-06-27) at
localhost:4567
</ADDRESS>
</BODY>
</HTML>
Any help would be greatly appreciated, thanks in advance!
The problem here is the Content-Length value is wrong - you are sending more data than that.
If you remove the last client.println(""); as it isn't needed, and increase Content-Length to either 16 or 17 (depends on what newline chars println adds) then it works.
A more portable approach would be to build the data you want to post in a String object, then set the Content-Length based on its .length().

How to use $filter in OData query

I have a problem consuming an OData-service in a Windows 8 store application.
If I do this:
IEnumerable<vw_mobSurveyor> lstSurveyors =
await ((DataServiceQuery<vw_mobSurveyor>)ODataContext.vw_mobSurveyor
.AddQueryOption("$filter", "intSurveyorID eq " + intID.ToString()))
.ExecuteAsync("GetByID").ConfigureAwait(false);
it works and the end of the URI is: /vw_mobSurveyor?$filter=intSurveyorID eq 1. This URI also works if I try it in a browser, so all is well.
But if I do :
IEnumerable<vw_mobSurveyor> lstSurveyors =
await ((DataServiceQuery<vw_mobSurveyor>)ODataContext.vw_mobSurveyor
.Where(s => s.intSurveyorID == intID))
.ExecuteAsync("GetByID").ConfigureAwait(false);
This fails with a Client Internal Error 4. It produces a different ending to the URI: /vw_mobSurveyor(2) This URI fails when I try it in a browser, and that is why it fails when the code generates it.
I have read these two should be equivalent in the produced URI: http://msdn.microsoft.com/en-us/library/ee622463.aspx#filtering.
As I would like to pass a Linq expression in future, so I need to get the second version to work. So how do I force the second version to use $filter so it works?
Update : Fiddler output for working code using $filter
HTTP/1.1 200 OK
Cache-Control: no-cache
Content-Length: 1057
Content-Type: application/atom+xml;type=feed;charset=utf-8
Server: Microsoft-IIS/7.0
X-Content-Type-Options: nosniff
DataServiceVersion: 1.0;
X-AspNet-Version: 4.0.30319
X-Powered-By: ASP.NET
Date: Fri, 18 Jan 2013 11:35:34 GMT
<?xml version="1.0" encoding="utf-8"?>
<feed xml:base="http://MYSERVER/TESTAPP%20V1/DataService.svc/"
xmlns="http://www.w3.org/2005/Atom"
xmlns:d="http://schemas.microsoft.com/ado/2007/08/dataservices"
xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata">
<id>http://MYSERVER/TESTAPP%20V1/DataService.svc/vw_mobSurveyor</id>
<title type="text">vw_mobSurveyor</title>
<updated>2013-01-18T11:35:34Z</updated>
<link rel="self" title="vw_mobSurveyor" href="vw_mobSurveyor" />
<entry>
<id>http://MYSERVER/TESTAPP%20V1/DataService.svc/vw_mobSurveyor(2)</id>
<category term="SurveyProModel.vw_mobSurveyor" scheme="http://schemas.microsoft.com/ado/2007/08/dataservices/scheme" />
<link rel="edit" title="vw_mobSurveyor" href="vw_mobSurveyor(2)" />
<title />
<updated>2013-01-18T11:35:34Z</updated>
<author>
<name />
</author>
<content type="application/xml">
<m:properties>
<d:intSurveyorID m:type="Edm.Int32">2</d:intSurveyorID>
<d:vchName>Bob Green 2</d:vchName>
<d:vchStatus>Surveyor</d:vchStatus>
</m:properties>
</content>
</entry>
</feed>
Update : Fiddler output for failing code
HTTP/1.1 200 OK
Cache-Control: no-cache
Content-Length: 824
Content-Type: application/atom+xml;type=entry;charset=utf-8
Server: Microsoft-IIS/7.0
X-Content-Type-Options: nosniff
DataServiceVersion: 1.0;
X-AspNet-Version: 4.0.30319
X-Powered-By: ASP.NET
Date: Fri, 18 Jan 2013 11:33:30 GMT
<?xml version="1.0" encoding="utf-8"?>
<entry xml:base="http://MYSERVER/TESTAPP%20V1/DataService.svc/"
xmlns="http://www.w3.org/2005/Atom"
xmlns:d="http://schemas.microsoft.com/ado/2007/08/dataservices"
xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata">
<id>http://MYSERVER/TESTAPP%20V1/DataService.svc/vw_mobSurveyor(2)</id>
<category term="SurveyProModel.vw_mobSurveyor" scheme="http://schemas.microsoft.com/ado/2007/08/dataservices/scheme" />
<link rel="edit" title="vw_mobSurveyor" href="vw_mobSurveyor(2)" />
<title />
<updated>2013-01-18T11:33:30Z</updated>
<author>
<name />
</author>
<content type="application/xml">
<m:properties>
<d:intSurveyorID m:type="Edm.Int32">2</d:intSurveyorID>
<d:vchName>Bob Green 2</d:vchName>
<d:vchStatus>Surveyor</d:vchStatus>
</m:properties>
</content>
</entry>
This seems like a bug in the WCF Data Services client.
At first glance, I don't see any issues in the Fiddler traces you provided, but I'll try to reproduce this on my end and I'll file an internal bug for this. If you have a full stack trace of the error, that would be very helpful.
Just to note: the LINQ-to-URI translation bit is doing the correct thing here. If a .Where clause is only checking the key value of an entity, we optimize the query by directly looking up the entity by its key (i.e., ../vw_mobSurveyor(2)) instead of using the $filter mechanism. This will result in an entry response payload instead of a feed, which matches what you got from Fiddler.
And to answer your original question, you could force the LINQ translator to use $filter by making the predicate involve anything other than the just the entity key. For example, you could do something like:
.Where(s => s.intSurveyorID == intID && true)
This is obviously a hack, but it should work. Ideally, we'll find and fix this bug and you can then use a more normal-looking Where clause :).
It looks like you are querying a view; have you set the entity key property in your entity model?

Can't get Savon to form the right XML

I've used SOAP before but many, many years ago and try to stay clear if I can help it.
Short story...
Using "Soap Client" OS X app I can get the response I wish.
If I use client.request :foo_web_serivce, :language_count, :body => { :foo_app_id => "...", :session_id => "..." } then I get a Status 200 but my results are -1 as I believe the app_id is not recognised.
If I try to replicate the Soap Client call (<LanguageCount>) rather than Savon's call (<foo_web_service:LanguageCount>) then I get an Status 500.
Please advise and thanks in advance.
Long Story...
Using SOAP Client I can see that the correct request XML is:
User-Agent: Mac OS X; WebServicesCore (357)
Content-Type: text/xml
Host: redacted
Soapaction: http://tempuri.org/redacted/LanguageCount
<?xml version="1.0" encoding="utf-8"?>
<SOAP-ENV:Envelope
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/"
SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
<SOAP-ENV:Body>
<LanguageCount xmlns="http://tempuri.org/">
<fooAppID xsi:type="xsd:string">12345678-1234-1234-1234-123456789123</fooAppID>
<sessionID xsi:type="xsd:string">12345678-1234-1234-1234-123456789123</sessionID>
</LanguageCount>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
However, when I try to do it in the console like so:
ruby-1.8.7-p302 > client = Savon::Client.new do |wsdl, http, wsse|
ruby-1.8.7-p302 > wsdl.document = "http://FooService.cloudapp.net/FooService.svc?wsdl"
ruby-1.8.7-p302 ?> end
=> #<Savon::Client:0x1055e2dc8 #http=#<HTTPI::Request:0x1055e2bc0>, #wsse=#<Savon::WSSE:0x1055e2b98>, #wsdl=#<Savon::WSDL::Document:0x1055e2c10 #request=#<HTTPI::Request:0x1055e2bc0>, #document="http://FooService.cloudapp.net/FooService.svc?wsdl">>
ruby-1.8.7-p302 >
ruby-1.8.7-p302 > client.request :language_count, :body => {:Foo_app_id => "12345678-1234-1234-1234-123456789123", :session_id => "12345678-1234-1234-1234-123456789123"}
Retrieving WSDL from: http://FooService.cloudapp.net/FooService.svc?wsdl
HTTPI executes HTTP GET using the net_http adapter
SOAP request: http://Fooservice.cloudapp.net/FooService.svc
SOAPAction: "LanguageCount", Content-Type: text/xml;charset=UTF-8
<?xml version="1.0" encoding="UTF-8"?><env:Envelope xmlns:wsdl="http://tempuri.org/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:env="http://schemas.xmlsoap.org/soap/envelope/"><env:Body><LanguageCount><FooAppId>12345678-1234-1234-1234-123456789123</FooAppId><sessionId>12345678-1234-1234-1234-123456789123</sessionId></LanguageCount></env:Body></env:Envelope>
HTTPI executes HTTP POST using the net_http adapter
SOAP response (status 500):
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/"><s:Body><s:Fault><faultcode xmlns:a="http://schemas.microsoft.com/ws/2005/05/addressing/none">a:ActionNotSupported</faultcode><faultstring xml:lang="en-US">The message with Action 'LanguageCount' cannot be processed at the receiver, due to a ContractFilter mismatch at the EndpointDispatcher. This may be because of either a contract mismatch (mismatched Actions between sender and receiver) or a binding/security mismatch between the sender and the receiver. Check that sender and receiver have the same contract and the same binding (including security requirements, e.g. Message, Transport, None).</faultstring></s:Fault></s:Body></s:Envelope>
Savon::SOAP::Fault: (a:ActionNotSupported) The message with Action 'LanguageCount' cannot be processed at the receiver, due to a ContractFilter mismatch at the EndpointDispatcher. This may be because of either a contract mismatch (mismatched Actions between sender and receiver) or a binding/security mismatch between the sender and the receiver. Check that sender and receiver have the same contract and the same binding (including security requirements, e.g. Message, Transport, None).
But when I use the namespace of foo_web_service, I get:
ruby-1.8.7-p302 > client = Savon::Client.new do |wsdl, http, wsse| ruby-1.8.7-p302 > wsdl.document = "http://FooService.cloudapp.net/FooService.svc?wsdl" ruby-1.8.7-p302 ?> end =>
#<Savon::Client:0x105882498 #http=#<HTTPI::Request:0x105882358>, #wsse=#<Savon::WSSE:0x105882330>, #wsdl=#<Savon::WSDL::Document:0x105882380 #request=#<HTTPI::Request:0x105882358>, #document="http://FooService.cloudapp.net/FooService.svc?wsdl">> ruby-1.8.7-p302 > ruby-1.8.7-p302 > client.request :Foo_web_service, :language_count, :body => {:Foo_app_id
=> "12345678-1234-1234-1234-123456789123", :session_id => "12345678-1234-1234-1234-123456789123"} Retrieving WSDL from: http://FooService.cloudapp.net/FooService.svc?wsdl HTTPI executes HTTP GET using the net_http adapter SOAP request: http://Fooservice.cloudapp.net/FooService.svc SOAPAction: "http://tempuri.org/FooService/LanguageCount", Content-Type: text/xml;charset=UTF-8 <?xml version="1.0" encoding="UTF-8"?><env:Envelope xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:Foo_web_service="http://tempuri.org/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:env="http://schemas.xmlsoap.org/soap/envelope/"><env:Body><Foo_web_service:LanguageCount><FooAppId>12345678-1234-1234-1234-123456789123</FooAppId><sessionId>12345678-1234-1234-1234-123456789123</sessionId></Foo_web_service:LanguageCount></env:Body></env:Envelope> HTTPI executes HTTP POST using the net_http adapter SOAP response (status 200): <s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/"><s:Body><LanguageCountResponse xmlns="http://tempuri.org/"><LanguageCountResult>-1</LanguageCountResult></LanguageCountResponse></s:Body></s:Envelope>
=> #<Savon::SOAP::Response:0x105a2cca8 #http=#<HTTPI::Response:0x105a28ce8 #body="<s:Envelope xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\"><s:Body><LanguageCountResponse xmlns=\"http://tempuri.org/\"><LanguageCountResult>-1</LanguageCountResult></LanguageCountResponse></s:Body></s:Envelope>", #raw_body="<s:Envelope xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\"><s:Body><LanguageCountResponse xmlns=\"http://tempuri.org/\"><LanguageCountResult>-1</LanguageCountResult></LanguageCountResponse></s:Body></s:Envelope>", #code=200, #headers={"x-powered-by"=>"ASP.NET", "x-aspnet-version"=>"4.0.30319", "content-type"=>"text/xml; charset=utf-8", "date"=>"Sat, 02 Jul 2011 23:40:56 GMT", "server"=>"Microsoft-IIS/7.0", "content-length"=>"214", "cache-control"=>"private"}>, #soap_fault=Savon::SOAP::Fault, #http_error=Savon::HTTP::Error> ruby-1.8.7-p302 >
Long story short, I had to make 3 changes.
Changed response = client.request :language_count to
response = client.request "LanguageCount"
Added :xmlns => "http://tempuri.org/" to the end of the client.request call
Explicitly called the SOAPaction like: client.http.headers["SOAPAction"] = '"http://tempuri.org/FooService/LanguageCount"'
Hope this helps someone as I've been in SOAP hell for the weekend and hopefully I'll stop someone else being there.

Resources