Google Contacts API with Service Account - c#

I am having trouble to Create a contact in google using google api v3.
I can successfully call cr.GetContacts() to get all the contacts (for the user I'm specifying), but cr.Insert is giving me the error:
Execution of request failed: https://www.google.com/m8/feeds/contacts/someuser#mydomain.com/full
Am I missing something?
string serviceAccountEmail = "111111111111-aaaa1a1aa11a1aaaaaaa11aaaa1aaa11#developer.gserviceaccount.com";
X509Certificate2 certificate = new X509Certificate2(#"C:\All\ContactsManager-1aa1bbb1ab11.p12", "notasecret", X509KeyStorageFlags.Exportable);
ServiceAccountCredential credential = new ServiceAccountCredential(new ServiceAccountCredential.Initializer(serviceAccountEmail)
{
Scopes = new[]
{
"https://www.google.com/m8/feeds"
},
User = "someuser#mydomain.com"
}.FromCertificate(certificate));
credential.RequestAccessTokenAsync(System.Threading.CancellationToken.None).Wait();
RequestSettings rs = new RequestSettings("ContactsManager", credential.Token.AccessToken);
//rs.AutoPaging = true;
ContactsRequest cr = new ContactsRequest(rs);
//var contacts = cr.GetContacts(); //////THIS LINE WORKS AND GETS ALL THE CONTACTS
Uri feedUri = new Uri(ContactsQuery.CreateContactsUri("someuser#mydomain.com"));
//feedUri will now be https://www.google.com/m8/feeds/contacts/someuser%40mydomain.com/full
Contact createdEntry = cr.Insert(feedUri, newContact);
Console.WriteLine("Contact's ID: " + createdEntry.Id);

EDIT: I figured out the problem, just want to update for anybody else who has the same issue.
If you followed the v3 documentation for creating a contact: they have a section on that contact entity like this:
newEntry.IMs.Add(new IMAddress()
{
Primary = true,
Rel = ContactsRelationships.IsHome,
Protocol = ContactsProtocols.IsGoogleTalk,
});
if you remove this IMAddress, then the contact creates fine.

Related

Create domain shared contact in Gsuite using Contacts API in C#

I am trying to create a domain shared contact in GSuite via the Contacts API in C# but unable to figure out how to POST the atom XML entry to the Feed URL as mentioned here : https://developers.google.com/admin-sdk/domain-shared-contacts/#Creating
I have tried following the older GData way mentioned here https://developers.google.com/gdata/client-cs but I get a "Execution of authentication request returned unexpected result: 404" error.
static void Main(string[] args)
{
Console.WriteLine("Hello !! ");
//Get Auth
OAuth2Parameters p = ContactsAuth();
//Create a domain shared contact
try
{
RequestSettings settings = new RequestSettings("GSuiteAdminApp", p);
ContactsRequest cr = new ContactsRequest(settings);
ContactEntry cn = new ContactEntry();
Name n = new Name();
n.GivenName = "Ice";
n.FamilyName = "Cold001";
n.FullName = "Ice Cold001";
EMail e = new EMail();
e.Rel = "http://schemas.google.com/g/2005#work";
e.Primary = true;
e.Address = "ice.cold001#xyz.com";
cn.Name = n;
cn.Emails.Add(e);
}
catch (Exception e44)
{
Console.WriteLine(e44.Message);
}
}
//Auth for Contacts API
public static OAuth2Parameters ContactsAuth()
{
string clientId = "xxxxxxxxxxxxxx.apps.googleusercontent.com";
string clientSecret = "xxxxxxxxxxxxx";
string[] scopes = new string[] { "https://www.google.com/m8/feeds/" };
try
{
UserCredential credential = GoogleWebAuthorizationBroker.AuthorizeAsync(new ClientSecrets
{
ClientId = clientId,
ClientSecret = clientSecret
}, scopes, "super-admin#mydomain.com", CancellationToken.None, new FileDataStore("C:\\Temp\\A\\SharedContactsOauth")).Result;
// Translate the Oauth permissions to something the old client libray can read
OAuth2Parameters parameters = new OAuth2Parameters();
parameters.AccessToken = credential.Token.AccessToken;
parameters.RefreshToken = credential.Token.RefreshToken;
return parameters;
}
catch (Exception ex33)
{
Console.WriteLine(ex33.Message);
return null;
}
}
This gives a "request failed" error.
I was finally able to figure it out by stringing along code snippets from few different sources and some modifications of my own. Linda Lawton's https://www.daimto.com/google-contacts-with-c/ for the OAuth2 part using older GData API. Google's documentation on Contacts API v3.0 https://developers.google.com/contacts/v3/ for mechanics of using the .NET client library for contacts and their (bit sketchy) documentation on "domain shared contacts", especially on using the proper FeedUri and Atom entries for new contact https://developers.google.com/admin-sdk/domain-shared-contacts/#Creating.
Basically what it boils down to is this -
Use a GSuite Super Admin account to authrorize to Contacts API using OAuth2.0, then use GData Contacts .NET client library to create the new contact
by suppying your Gsuite domain in the method and you are done.
Here's the full code which I have it working for me now:
using System;
using System.Threading;
using Google.Contacts;
using Google.GData.Contacts;
using Google.GData.Client;
using Google.GData.Extensions;
using Google.Apis.Auth;
using Google.Apis.Auth.OAuth2;
using Google.Apis.Util.Store;
namespace SharedContactsAPI
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Hello !! ");
//Get Auth
OAuth2Parameters p = ContactsAuth();
////Create a domain shared contact
try
{
RequestSettings settings = new RequestSettings("GSuiteAdminApp", p);
ContactsRequest contactreq = new ContactsRequest(settings);
Console.WriteLine("Attempting to create a Domain Shared Contact in GSuite");
Console.WriteLine(" ");
CreateContact(contactreq);
}
catch (Exception e44)
{
Console.WriteLine(e44.Message);
}
}
//Create Shared Contact
public static Contact CreateContacttest(ContactsRequest cr)
{
Contact newEntry = new Contact();
// Set the contact's name.
newEntry.Name = new Name()
{
FullName = "Ice Cold005",
GivenName = "Ice",
FamilyName = "Cold005"
};
newEntry.Content = "Notes";
// Set the contact's e-mail addresses.
newEntry.Emails.Add(new EMail()
{
Primary = true,
Rel = ContactsRelationships.IsWork,
Address = "ice.cold005#xyz.com"
});
//Insert the contact
Uri feedUri = new Uri(ContactsQuery.CreateContactsUri("test.com"));
Contact createdEntry = cr.Insert(feedUri, newEntry);
Console.WriteLine("New Contact created successfully with ContactID = " + createdEntry.Id);
return createdEntry;
}
//Auth for Contacts API
public static OAuth2Parameters ContactsAuthtest()
{
string clientId = "xxxxxxxxxxxxxxxxxxxxx.apps.googleusercontent.com";
string clientSecret = "xxxxxxxxxxxxxxxxxxxxxxxxxx";
string[] scopes = new string[] { "https://www.google.com/m8/feeds/contacts/" };
try
{
UserCredential credential = GoogleWebAuthorizationBroker.AuthorizeAsync(new ClientSecrets
{
ClientId = clientId,
ClientSecret = clientSecret
}, scopes, "super-admin#test.com", CancellationToken.None, new FileDataStore("C:\\Temp\\A\\SharedContactsOauth")).Result;
// Translate the Oauth permissions to something the old client libray can read
OAuth2Parameters parameters = new OAuth2Parameters();
parameters.AccessToken = credential.Token.AccessToken;
parameters.RefreshToken = credential.Token.RefreshToken;
return parameters;
}
catch (Exception ex33)
{
Console.WriteLine(ex33.Message);
return null;
}
}
}
}

Google Contacts API returns list of email addresses I sent to, but not those in my Contacts list?

Google Contacts API returns list of email addresses I sent to, but not those in my Contacts list?
I'm using google contact api and try to get the list of emails in my gmail contacts. The google contact is at https://contacts.google.com/u/0/preview/all .
Below it is the code I use:
public List<GMail> GetContacts(GooglePlusAccessToken serStatus)
{
List<GMail> ret = new List<GMail>();
string google_client_id = _ClientId;
string google_client_sceret = _ClientSeceret;
string refreshToken = serStatus.refresh_token;
string accessToken = serStatus.access_token;
string scopes = "https://www.google.com/m8/feeds/contacts/default/full/";
OAuth2Parameters oAuthparameters = new OAuth2Parameters()
{
ClientId = google_client_id,
ClientSecret = google_client_sceret,
RedirectUri = GetRedirectUrl(),
Scope = scopes,
AccessToken = accessToken,
RefreshToken = refreshToken
};
RequestSettings settings = new RequestSettings("<var>Invite GMail Friends</var>", oAuthparameters);
ContactsRequest cr = new ContactsRequest(settings);
ContactsQuery query = new ContactsQuery(ContactsQuery.CreateContactsUri("default"));
query.NumberToRetrieve = _NumberToRetrieve;
Feed<Contact> feed = cr.Get<Contact>(query);
foreach (Contact entry in feed.Entries)
{
foreach (EMail email in entry.Emails)
{
GMail g = new GMail(email.Address);
ret.Add(g);
}
}
return ret;
}
But for some reasons, the code returns the list of email addresses that I sent to in the past, but not the emails in my contact list. Is this correct? Anyone knows why?
Thanks
** Thanks for Allen's answer, here is my code, and it works great! The contact group is actually: SystemGroup:MyContacts#gmail.com**
public List<GMail> GetContacts_2(GooglePlusAccessToken serStatus)
{
List<GMail> ret = new List<GMail>();
string google_client_id = _ClientId;
string google_client_sceret = _ClientSeceret;
/*Get Google Contacts From Access Token and Refresh Token*/
string refreshToken = serStatus.refresh_token;
string accessToken = serStatus.access_token;
string scopes = "https://www.google.com/m8/feeds/groups/default/full/?v=3.0";
OAuth2Parameters oAuthparameters = new OAuth2Parameters()
{
ClientId = google_client_id,
ClientSecret = google_client_sceret,
RedirectUri = GetRedirectUrl(),
Scope = scopes,
AccessToken = accessToken,
RefreshToken = refreshToken
};
RequestSettings settings = new RequestSettings("<var>Invite GMail Friends</var>", oAuthparameters);
ContactsRequest cr = new ContactsRequest(settings);
GroupsQuery query = new GroupsQuery(GroupsQuery.CreateGroupsUri("default"));
query.NumberToRetrieve = 1000; // _NumberToRetrieve; // 100;// 5000;
//Feed feed = cr.Get(query);
Feed<Group> feed = cr.Get<Group>(query);
string gpId = string.Empty;
foreach (Group gp in feed.Entries)
{
if (gp.Title.Contains("Contacts"))
{
gpId = gp.Id;
//break;
}
//// for testing
//GMail g = new GMail(gp.Title.Replace(" ", "") + "#gmail.com");
//ret.Add(g);
}
if (gpId.Length > 0)
{
scopes = "https://www.google.com/m8/feeds/contacts/default/full/?v=3.0";
oAuthparameters = new OAuth2Parameters()
{
ClientId = google_client_id,
ClientSecret = google_client_sceret,
RedirectUri = GetRedirectUrl(),
Scope = scopes,
AccessToken = accessToken,
RefreshToken = refreshToken
};
settings = new RequestSettings("<var>Invite GMail Friends</var>", oAuthparameters);
//ContactsRequest cr = new ContactsRequest(settings);
cr = new ContactsRequest(settings);
ContactsQuery query2 = new ContactsQuery(ContactsQuery.CreateContactsUri("default"));
query2.NumberToRetrieve = _NumberToRetrieve; // 100;// 5000;
query2.OrderBy = ContactsQuery.OrderByLastModified;
query2.SortOrder = ContactsQuery.SortOrderDescending;
query2.Group = gpId;
Feed<Contact> feed2 = cr.Get<Contact>(query2);
foreach (Contact entry in feed2.Entries)
{
foreach (EMail email in entry.Emails)
{
GMail g = new GMail(email.Address);
ret.Add(g);
}
}
//if (ret.Count <= 0)
//{
// GMail g = new GMail("NoContact#gmail.com");
// ret.Add(g);
//}
}
//else
//{
// // for testing
// GMail g = new GMail("NoGroup#gmail.com");
// ret.Add(g);
//}
return ret;
}
To start with, I feel your pain. Google's APIs are the worst. Period.
The way I got around it (not an efficient way of doing things but this is the best I could find. Else Google returns all those bogus contact emails that were ever communicated with the account holder, could be thousands of such entries in a typical GMail account)) is this (its VB.net code but you can get a gist and convert easily)
FIRST RETRIEVE CONTACT GROUPS AND LOOK FOR THE TITLE "CONTACTS"
Dim settings As New RequestSettings("MyApp", RefreshOAuthToken())
Dim cr As New ContactsRequest(settings)
'retrieve Contacts group (this is to retrieve only real contacts)
Dim groupquery As New GroupsQuery(GroupsQuery.CreateGroupsUri("default"))
Dim fgrp As Feed(Of Group) = cr.Get(Of Group)(groupquery)
Dim GroupAtomId As String = ""
For Each gr In fgrp.Entries
If gr.Title.Contains("Contacts") Then
GroupAtomId = gr.Id
Exit For
End If
Next
THEN USE THE ID OF THE CONTACT GROUP TO SEARCH IN CONTACT
Dim query As New ContactsQuery(ContactsQuery.CreateContactsUri("default"))
query.NumberToRetrieve = 2000
query.OrderBy = ContactsQuery.OrderByLastModified
query.SortOrder = ContactsQuery.SortOrderDescending
query.Group = GroupAtomId
Dim f As Feed(Of Contact) = cr.Get(Of Contact)(query)
For Each entry As Contact In f.Entries
'Do something with the data, these are real contacts in GMail
Next
So the point here is to first get the group id and use it in contact search. I believe this is what your code is missing.

Adding User to Organization Unit and Group using Google Directory API

I am successful to create new user account using Google Directory API in .Net platform, but now I need to add that created user to Organization Unit and Group. I see the API details in this link to add the user to Organization Unit but any example showing insertion to Organization Unit would be greatly appreciated.
Updated with working code: Below is the code to create new user account using Directory API:
String serviceAccountEmail = ".........#developer.gserviceaccount.com";
X509Certificate2 certificate = new X509Certificate2(#"C:\key.p12", "secret", X509KeyStorageFlags.Exportable);
ServiceAccountCredential credential = new ServiceAccountCredential(new ServiceAccountCredential.Initializer(serviceAccountEmail)
{
Scopes = new[]
{
DirectoryService.Scope.AdminDirectoryUser
},
User = "test#example.com",
}.FromCertificate(certificate));
var ser = new DirectoryService(new BaseClientService.Initializer()
{
HttpClientInitializer = credential,
ApplicationName = "Google Account",
});
try
{
var user = new Google.Apis.Admin.Directory.directory_v1.Data.User()
{
Name = new Google.Apis.Admin.Directory.directory_v1.Data.UserName()
{
GivenName = FirstName.Text,
FamilyName = LastName.Text
},
Password = password
};
User newUser = new User();
UserName newUserName = new UserName();
newUser.PrimaryEmail = Email.Text;
newUserName.GivenName = FirstName_txt.Text;
newUserName.FamilyName = LastName_txt.Text;
newUser.Name = newUserName;
newUser.Password = password;
//Adding User to OU:
newUser.OrgUnitPath = "/Employee";
User results = ser.Users.Insert(newUser).Execute();
//Adding User to Group:
Member newMember = new Member();
newMember.Email = Email.Text;
newMember.Role = "MEMBER";
newMember.Kind = "admin#directory#member";
api.Members.Insert(newMember, "Employee#example.com").Execute();
Any idea how to insert the created user in Organization Unit and Group using Directory API?
To insert the new user into a Organization Unit just set the OU path when you create the user.
User newUser = new User();
UserName newUserName = new UserName();
newUser.PrimaryEmail = Email.Text;
newUserName.GivenName = FirstName_txt.Text;
newUserName.FamilyName = LastName_txt.Text;
newUser.Name = newUserName;
newUser.Password = password;
**newUser.OrgUnitPath ="\My\Organization\Unit\path\";**
User results = ser.Users.Insert(newUser).Execute();
Now your user has been added to the OU path.
To add a member into a group see the following code.
Member newMember = new Member();
newMember.Email = userKey;//email of the user that you want to add
newMember.Role = "MEMBER";
newMember.Type = "USER";
newMember.Kind = "admin#directory#member";
ser.Members.Insert(newMember, "MyDestinationGroup#mydomain").Execute();
that's it.
Note: you must review the scopes for the correct permissions.
Hope this help you.

C# EWS copy contacts to a mailbox

I want to select the user "test" so I can create a contact into his mailbox.
My actual problem is that it will create Contacts into my user "c-sharp".
"c-sharp" has full access on "test" mailbox
I changed the IP and the contact infos users are also only for testing.
ExchangeService service = new ExchangeService(ExchangeVersion.Exchange2013);
service.TraceEnabled = true;
service.TraceFlags = TraceFlags.All;
service.EnableScpLookup = false;
service.Credentials = new WebCredentials("c-sharp", "c-sharp", "domain");
service.UseDefaultCredentials = false;
IgnoreBadCertificates();
service.Url = new Uri("https://192.000.000.000/EWS/Exchange.asmx");
Contact contact = new Contact(service);
// Specify the name and how the contact should be filed.
contact.GivenName = "n.a.";
contact.FileAsMapping = FileAsMapping.SurnameCommaGivenName;
contact.DisplayName = "bau gmbh";
// Specify the company name.
contact.CompanyName = "bau";
// Specify the business, home, and car phone numbers.
contact.PhoneNumbers[PhoneNumberKey.BusinessPhone] = "00000 00000";
contact.PhoneNumbers[PhoneNumberKey.MobilePhone] = "n.a.";
contact.PhoneNumbers[PhoneNumberKey.BusinessFax] = "00000 00000";
// Specify two email addresses.
contact.EmailAddresses[EmailAddressKey.EmailAddress1] = new EmailAddress("e#mail.de");
//homepage
contact.BusinessHomePage = "n.a.";
// Specify the home address.
PhysicalAddressEntry paEntry1 = new PhysicalAddressEntry();
paEntry1.Street = "straße";
paEntry1.City = "stadt";
paEntry1.State = "D";
paEntry1.PostalCode = "88890";
paEntry1.CountryOrRegion = "Deutschland";
contact.PhysicalAddresses[PhysicalAddressKey.Home] = paEntry1;
contact.Save();
Already tried this:
service.ImpersonatedUserId = new ImpersonatedUserId(ConnectingIdType.PrincipalName, "test");
I tested it with "test" and "test#domain" and "test#domain.de"
And get back this error:
"Der Name des Identitätsprinzipals ist ungültig."
Own translation: "The name of the identity principal is unvailed"
You can use Impersonation like this
ExchangeUserData exchangeUserData = new ExchangeUserData();
exchangeUserData.Username = "c-sharp";
exchangeUserData.Password = "c-sharp"; // c-sharp's Password
ExchangeService service = Service.ConnectToServiceWithImpersonation(exchangeUserData, impersonatedUserPrincipal);
Contact contact = new Contact(service);
// Specify the name and how the contact should be filed.
contact.GivenName = "n.a.";
contact.FileAsMapping = FileAsMapping.SurnameCommaGivenName;
contact.DisplayName = "bau gmbh";
// Specify the company name.
contact.CompanyName = "bau";
// Specify the business, home, and car phone numbers.
contact.PhoneNumbers[PhoneNumberKey.BusinessPhone] = "00000 00000";
contact.PhoneNumbers[PhoneNumberKey.MobilePhone] = "n.a.";
contact.PhoneNumbers[PhoneNumberKey.BusinessFax] = "00000 00000";
// Specify two email addresses.
contact.EmailAddresses[EmailAddressKey.EmailAddress1] = new EmailAddress("e#mail.de");
//homepage
contact.BusinessHomePage = "n.a.";
// Specify the home address.
PhysicalAddressEntry paEntry1 = new PhysicalAddressEntry();
paEntry1.Street = "straße";
paEntry1.City = "stadt";
paEntry1.State = "D";
paEntry1.PostalCode = "88890";
paEntry1.CountryOrRegion = "Deutschland";
contact.PhysicalAddresses[PhysicalAddressKey.Home] = paEntry1;
contact.Save();
If your c-sharp user has the proper rights in Exchange, you should be able to do:
ExchangeService service = new ExchangeService(ExchangeVersion.Exchange2013);
service.Credentials = new WebCredentials("c-sharp", "c-sharp", "domain");
service.ImpersonatedUserId = new ImpersonatedUserId(ConnectingIdType.PrincipalName, "test");
If this doesn't work for you, please comment below or update your question (there's an "edit" link under it) with the exact behavior you are seeing including any error messages.
Problem sloved.
I found the bug... both of you are right just change:
service.ImpersonatedUserId = new ImpersonatedUserId(ConnectingIdType.PrincipalName, "test");
Into:
service.ImpersonatedUserId = new ImpersonatedUserId(ConnectingIdType.SmtpAddress, "test#domain.de");
Thats all ...
Great thanks to you

Is there any Twitterizer 2.4.2.dll available?

I am working on a app in which user will search in twitter throw my app. but i could not found any Twitterizer 2.4.2.dll i found only package manager installer every where i have vs 2008 in vs 2008 there is not a pk manager
some of sites tell alternative of pk manager but those are long processess.
i want short solution is there any Twitterizer 2.4.2.dll available ??? so that i connect with twitter
OR there any other way to connect with twitter ??? istead of Twitterizer 2.4.2 ??
at the momnet i am using LinqtoTwitter.dll my code is
static void Main(string[] args)
{
var auth = new ApplicationOnlyAuthorizer
{
Credentials = new InMemoryCredentials
{
ConsumerKey = "xxxx",
ConsumerSecret = "xxxx"
}
};
var twitterCtx = new TwitterContext(auth);
var queryResults =
from search in twitterCtx.Search
where search.Type == SearchType.Search &&
search.Query == "Linq To Twitter"
select search;
Search srch = queryResults.Single();
srch.Statuses.ForEach(entry =>
Console.WriteLine(
"ID: {0, -15}, Source: {1}\nContent: {2}\n",
entry.StatusID, entry.Source, entry.Text));
Console.ReadKey();
}
but it is giving me `Bad Authentication data
Exception
is there opensource dll availabe so that i connect with twitter not with pk manager ??? `
With the ApplicationOnlyAuthorizer, you must call Authorize(), like this:
var auth = new ApplicationOnlyAuthorizer
{
Credentials = new InMemoryCredentials
{
ConsumerKey = "xxxx",
ConsumerSecret = "xxxx"
}
};
auth.Authorize();
var twitterCtx = new TwitterContext(auth);

Categories

Resources