Search code examples
asp.net-mvc-3c#-4.0oauthgdata-api

Authenticating correctly to get at Google Contacts... (C#/MVC3)


I have a very simple MVC app at this point:
Controller:

public class HomeController : Controller
{
    public ActionResult Index()
    {
        ViewBag.Message = "Welcome!";

        var qs = HttpContext.Request.QueryString;
        var keys = qs.AllKeys.ToList();
        if (keys.Count > 0 && keys.Contains("token"))
        {
            Session["token"] = qs.Get("token");
            Models.GoogleContact gc = new Models.GoogleContact();
        }
        else
        {
            ViewBag.GoogleUrl = AuthSubUtil.getRequestUrl(HttpContext.Request.Url.AbsoluteUri, "https://www.google.com/m8/feeds/", false, true);
        }

        return View();
    }

    public ActionResult About()
    {
        return View();
    }
}

I have this Home View:

@{
    ViewBag.Title = "Home Page";
}

<p>Home Page...</p>

<a href="@ViewBag.GoogleUrl">Tie in with Google</a>
<br />
<br />

When the app first launches there is no query string so the Controller will create the link that I embed on the Home page. You click the link and it shoots you off to Google. Authorize that you wish for this app to have access to the Google Contacts and it returns with a query string back to the home page. The Controller sees the query string, strips off the token and instantiates a Google "Model" class.

Base Class:

internal class baseGoogle
{
    #region Private Properties
    internal const string googleContactToken = "cp";
    internal const string googleCalendarToken = "cl";
    internal string _authSubToken;
    internal GAuthSubRequestFactory _gAuthSubRequestFactory;
    internal RequestSettings _requestSettings;
    internal ContactsRequest _contactsRequest;
    internal ContactsService _contactsService;
    #endregion

    internal baseGoogle()
    {
#if DEBUG
        _authSubToken = HttpContext.Current.Session["token"].ToString();
        _gAuthSubRequestFactory = new Google.GData.Client.GAuthSubRequestFactory(googleContactToken, "Tester1");
        _requestSettings = new Google.GData.Client.RequestSettings(_gAuthSubRequestFactory.ApplicationName, _authSubToken);
        _contactsRequest = new Google.Contacts.ContactsRequest(_requestSettings);
        _contactsService = new Google.GData.Contacts.ContactsService(_gAuthSubRequestFactory.ApplicationName);
        _contactsService.RequestFactory = _gAuthSubRequestFactory;
#endif
    }
}

My Google Contacts Class:

internal class GoogleContact : baseGoogle
{
    #region Public Properties
    [NotMapped]
    public Dictionary<string, Group> Groups { get; set; }
    #endregion

    public GoogleContact() : base()
    {
        // Get the list of contact groups...
        _requestSettings.AutoPaging = true;
        Feed<Group> fg = _contactsRequest.GetGroups();

        foreach (Group g in fg.Entries)
        {
            this.Groups.Add(g.Title, g);
        }

    }
}

Everything appears to be working fine until I try to iterate the Feed items. It pops a 401 - Unauthorized error at that point.

Any ideas of why it is doing this? I am following the docs up on Google Dev.

I am using the 1.7.0.1 version of the APIs.


NOTE: I found a blog entry with some different code and guess what, that works. Now to figure out why the semi-official way does not work! Anyone with any ideas?


Solution

  • After a lot of playing around I discovered one way to accomplish what I needed. First off, I could not discover a way to use the OpenID authorization token to get at that users contacts, calendar, etc. I am still looking for a way to do that. (see my question here)

    What I did figure out was to have a person enter his google username and password in his profile then use that to connect via GData to their info. My feeling is most people would NOT want to do this! (And it is rather redundant!)

    Here is the code I came up with:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using Google.GData.Contacts;
    using Google.GData.Extensions;
    
    namespace myNameSpace
    {
        /// 
        /// Summary description for GoogleContactService
        /// 
        public class GoogleContactService
        {
            #region Properties
            public static ContactsService GContactService = null;
            #endregion
    
            #region Methods
            public static void InitializeService(string username, string password)
            {
                GContactService = new ContactsService("Contact Infomation");
                GContactService.setUserCredentials(username, password);
            }
            public static List<ContactDetail> GetContacts(string GroupName = null)
            {
                List<ContactDetail> contactDetails = new List<ContactDetail>();
                ContactsQuery contactQuery = new ContactsQuery(ContactsQuery.CreateContactsUri("default"));
                contactQuery.NumberToRetrieve = 1000;
    
                if (!String.IsNullOrEmpty(GroupName))
                {
                    GroupEntry ge = GetGroup(GroupName);
                    if (ge != null)
                        contactQuery.Group = ge.Id.AbsoluteUri;
                }
                else
                {
                    string groupName = "";
                    GroupEntry ge = GetGroup(groupName);
                    if (ge != null)
                        contactQuery.Group = ge.Id.AbsoluteUri;
                }
    
                ContactsFeed feed = GContactService.Query(contactQuery);
                foreach (ContactEntry entry in feed.Entries)
                {
                    ContactDetail contact = new ContactDetail
                    {
                        Name = entry.Title.Text,
                        EmailAddress1 = entry.Emails.Count >= 1 ? entry.Emails[0].Address : "",
                        EmailAddress2 = entry.Emails.Count >= 2 ? entry.Emails[1].Address : "",
                        Phone1 = entry.Phonenumbers.Count >= 1 ? entry.Phonenumbers[0].Value : "",
                        Phone2 = entry.Phonenumbers.Count >= 2 ? entry.Phonenumbers[1].Value : "",
                        Address = entry.PostalAddresses.Count >= 1 ? entry.PostalAddresses[0].FormattedAddress : "",
                        Details = entry.Content.Content
                    };
    
                    contact.UserDefinedFields = new List<UDT>();
                    foreach ( var udt in entry.UserDefinedFields)
                    {
                        contact.UserDefinedFields.Add(new UDT { Key = udt.Key, Value = udt.Value });
                    }
    
                    contactDetails.Add(contact);
                }
    
                return contactDetails;
            }
            #endregion
    
            #region Helpers
            private static GroupEntry GetGroup(string GroupName)
            {
                GroupEntry groupEntry = null;
    
                GroupsQuery groupQuery = new GroupsQuery(GroupsQuery.CreateGroupsUri("default"));
                groupQuery.NumberToRetrieve = 100;
                GroupsFeed groupFeed = GContactService.Query(groupQuery);
                foreach (GroupEntry entry in groupFeed.Entries)
                {
                    if (entry.Title.Text.Equals(GroupName, StringComparison.CurrentCultureIgnoreCase))
                    {
                        groupEntry = entry;
                        break;
                    }
                }
                return groupEntry;
            }
            #endregion
        }
    
        public class ContactDetail
        {
            public string Name { get; set; }
            public string EmailAddress1 { get; set; }
            public string EmailAddress2 { get; set; }
            public string Phone1 { get; set; }
            public string Phone2 { get; set; }
            public string Address { get; set; }
            public string Details { get; set; }
            public string Pipe { get; set; }
            public string Relationship { get; set; }
            public string Status { get; set; }
            public List<UDT> UserDefinedFields { get; set; }
        }
        public class UDT
        {
            public string Key { get; set; }
            public string Value { get; set; }
        }
    }
    

    Now, to figure out how to use their OpenID login instead of having to ask for their login credentials!