Ebeo / google-gdata

Automatically exported from code.google.com/p/google-gdata
0 stars 0 forks source link

Updating contact entry in .NET fails when entry has "google_apps_sync" extended property defined #354

Closed GoogleCodeExporter closed 9 years ago

GoogleCodeExporter commented 9 years ago
What steps will reproduce the problem?
1. generate a 3-legged OAuth request for a user's full contact feed using
the .NET GData components (using the standard GData objects for .NET like
GOAuthRequestFactory, OAuthUri, ContactsService, ContactsQuery,
ContactsFeed, and ContactEntry.
2. When iterating through that feed, examining each entry in that feed,
make an arbitrary change to one of them (entry.Emails[0].Address =
"changedemail@company.com"; for example).  The key is to make sure that
this particular entry has a "google_apps_sync" extended property
(<gd:extendedProperty gs="http://schemas.google_apps_sync.com/contact/2008"
name="google_apps_sync" ...>)
3. Update the entry using the ContactsService.EntrySend() method and it
should fail with a "400 Bad Request" message.  The specific error message
returned about the malformed XMl request when you analyze the
GData.Client.GDataRequestException.RequestString is "[Line ??, Column ??,
element gd:extendedProperty] g:extendedProperty/@value and XML are mutually
exclusive"

Here's the code I'm using to verify the entry about to be updated has the
google_apps_sync extended property and if it does, it will update the entry
using the SendEntry() command:

for (int i = 0; i < entry.ExtendedProperties.Count; i++)
    if (entry.ExtendedProperties[i].Name == "google_apps_sync")
    {
        System.IO.Stream updateStream = service.EntrySend(new
OAuthUri(entry.EditUri.ToString().Replace("http://", "https://"), userId,
"company.com"), entry, GDataRequestType.Update);
        updateStream.Close();
    }

If you add this line right before the EntrySend(...) call then it works
fine and the best part is that the value being changed here doesn't
actually change the contact entry at all (the next time you run the code it
will fail again without the line below:
    entry.ExtendedProperties[i].Value == "";

I think the problem is that the Value attribute of the
<gd:ExtendedProperties ... name="google_apps_sync> tag shouldn't be there
but for some reason the SendEntry() method generates an update request with
all the values of the <gs:...> tags within the gd:ExtendedPropery tag. 
Here's the actual request that SendEntry() generates when the error occurs:

<?xml version="1.0" encoding="utf-8"?>
<entry xmlns="http://www.w3.org/2005/Atom"
xmlns:gd="http://schemas.google.com/g/2005" gd:etag="&quot;ETAG_HERE&quot;">
  <app:edited app="http://www.w3.org/2007/app"
xmlns:app="http://www.w3.org/2007/app">2009-10-22T14:31:35.775Z</app:edited>
  <gd:organization rel="http://schemas.google.com/g/2005#work">
  <gd:orgName>COMPANY_NAME_HERE</gd:orgName>
  </gd:organization>
  <gd:email address="CONTACT_EMAIL_ADDRESS_HERE"
rel="http://schemas.google.com/g/2005#work" />
  <gd:extendedProperty
gs="http://schemas.google_apps_sync.com/contact/2008"
name="google_apps_sync" value="&#xA;    CONTACT_EMAIL_ADDRESS_HERE&#xA;   
CONTACT_ACCOUNTNAME (CONTACT_EMAIL_ADDRESS_HERE)&#xA;   
CONTACT_EMAIL_ADDRESS_HERE&#xA; 
    <gs:em_odn1
xmlns:gs="http://schemas.google_apps_sync.com/contact/2008">CONTACT_EMAIL_ADDRES
S_HERE</gs:em_odn1>
    <gs:em_dn1
xmlns:gs="http://schemas.google_apps_sync.com/contact/2008">CONTACTG_ACCOUNTNAME
(CONTACT_EMAIL_ADDRESS_HERE)</gs:em_dn1>
    <gs:em_ad1
xmlns:gs="http://schemas.google_apps_sync.com/contact/2008">CONTACT_EMAIL_ADDRES
S_HERE</gs:em_ad1>
    <gs:em_t1
xmlns:gs="http://schemas.google_apps_sync.com/contact/2008">SMTP</gs:em_t1>
    <gs:f_c
xmlns:gs="http://schemas.google_apps_sync.com/contact/2008">32791</gs:f_c>
    <gs:f
xmlns:gs="http://schemas.google_apps_sync.com/contact/2008">LAST_NAME,
FIRST_NAME</gs:f>
  </gd:extendedProperty>
  <gContact:groupMembershipInfo deleted="false"
href="http://www.google.com/m8/feeds/groups/accountname%40company.com/base/6"
xmlns:gContact="http://schemas.google.com/contact/2008" />
  <title type="text">CONTACT_NAME_HERE</title>

<id>http://www.google.com/m8/feeds/contacts/accountname%40company.com/base/CONTA
CT_ID_HERE</id>
  <link
href="http://www.google.com/m8/feeds/photos/media/accountname%40company.com/CONT
ACT_ID_HERE"
rel="http://schemas.google.com/contacts/2008/rel#photo" type="image/*" />
  <link
href="http://www.google.com/m8/feeds/contacts/accountname%40company.com/full/CON
TACT_ID_HERE"
rel="self" type="application/atom+xml" />
  <link
href="http://www.google.com/m8/feeds/contacts/accountname%40company.com/full/CON
TACT_ID_HERE"
rel="edit" type="application/atom+xml" />
  <category term="http://schemas.google.com/contact/2008#contact"
scheme="http://schemas.google.com/g/2005#kind" />
  <content type="text" />
  <updated>2009-10-22T09:31:35-05:00</updated>
</entry>

I think this is what the correct XML update request should be (this request
actually works).  Line 8 is what's been changed:

<?xml version="1.0" encoding="utf-8"?>
<entry xmlns="http://www.w3.org/2005/Atom"
xmlns:gd="http://schemas.google.com/g/2005" gd:etag="&quot;ETAG_HERE&quot;">
  <app:edited app="http://www.w3.org/2007/app"
xmlns:app="http://www.w3.org/2007/app">2009-10-22T14:31:35.775Z</app:edited>
  <gd:organization rel="http://schemas.google.com/g/2005#work">
  <gd:orgName>COMPANY_NAME_HERE</gd:orgName>
  </gd:organization>
  <gd:email address="CONTACT_EMAIL_ADDRESS_HERE"
rel="http://schemas.google.com/g/2005#work" />
  <gd:extendedProperty
gs="http://schemas.google_apps_sync.com/contact/2008" name="google_apps_sync">
    <gs:em_odn1
xmlns:gs="http://schemas.google_apps_sync.com/contact/2008">CONTACT_EMAIL_ADDRES
S_HERE</gs:em_odn1>
    <gs:em_dn1
xmlns:gs="http://schemas.google_apps_sync.com/contact/2008">CONTACTG_ACCOUNTNAME
(CONTACT_EMAIL_ADDRESS_HERE)</gs:em_dn1>
    <gs:em_ad1
xmlns:gs="http://schemas.google_apps_sync.com/contact/2008">CONTACT_EMAIL_ADDRES
S_HERE</gs:em_ad1>
    <gs:em_t1
xmlns:gs="http://schemas.google_apps_sync.com/contact/2008">SMTP</gs:em_t1>
    <gs:f_c
xmlns:gs="http://schemas.google_apps_sync.com/contact/2008">32791</gs:f_c>
    <gs:f
xmlns:gs="http://schemas.google_apps_sync.com/contact/2008">LAST_NAME,
FIRST_NAME</gs:f>
  </gd:extendedProperty>
  <gContact:groupMembershipInfo deleted="false"
href="http://www.google.com/m8/feeds/groups/accountname%40company.com/base/6"
xmlns:gContact="http://schemas.google.com/contact/2008" />
  <title type="text">CONTACT_NAME_HERE</title>

<id>http://www.google.com/m8/feeds/contacts/accountname%40company.com/base/CONTA
CT_ID_HERE</id>
  <link
href="http://www.google.com/m8/feeds/photos/media/accountname%40company.com/CONT
ACT_ID_HERE"
rel="http://schemas.google.com/contacts/2008/rel#photo" type="image/*" />
  <link
href="http://www.google.com/m8/feeds/contacts/accountname%40company.com/full/CON
TACT_ID_HERE"
rel="self" type="application/atom+xml" />
  <link
href="http://www.google.com/m8/feeds/contacts/accountname%40company.com/full/CON
TACT_ID_HERE"
rel="edit" type="application/atom+xml" />
  <category term="http://schemas.google.com/contact/2008#contact"
scheme="http://schemas.google.com/g/2005#kind" />
  <content type="text" />
  <updated>2009-10-22T09:31:35-05:00</updated>
</entry>

I should be clear that this second request doesn't actually change the
"Value" attribute of that contact because the very next time you run it
without intentionally clearing that "Value=..." part out, the Value="..."
junk is still there.

The .NET GData SDK is 1.4.0.2
The GData version is 2.0

(both the latest non-beta releases at this time)

I'm running the code on a Windows XP, SP2 machine.  I'm running the code
against the 3.5 .NET framework.

By the way, I have to use the SendEntry() command because of other known
issues using 3-legged OAuth to make changes (updates, deletes, etc)
specifically with the .NET SDK.  that issue is better clarified here:
http://code.google.com/p/google-gdata/issues/detail?id=333  and also here:
http://www.google.com/support/forum/p/apps-apis/thread?tid=6c1d54de69c213a9&hl=e
n&fid=6c1d54de69c213a900048204f5e7b803

This is a reference to a discussion board where I've been posting my progress:
http://www.google.com/support/forum/p/apps-apis/thread?tid=6c1d54de69c213a9&hl=e
n&fid=6c1d54de69c213a900048204f5e7b803

Original issue reported on code.google.com by benny.hauk on 17 Mar 2010 at 8:53

GoogleCodeExporter commented 9 years ago
Can you give me a fiddler2 trace of the request coming in? I need to see how 
that
app-sync extended element looks like when i need to parse it.

Tx

Frank

Original comment by fman...@gmail.com on 22 Mar 2010 at 4:39

GoogleCodeExporter commented 9 years ago
Checked in new DLs and source code and unittest for this case into subversion. 
There was a general issue with 
simplelement and it's subclasses (like gd:extendedproperty) that nested xml was 
not parsed correctly. As this 
case just did not exist before, nobody ever noticed :) 

Original comment by fman...@gmail.com on 24 Mar 2010 at 11:02