Knowledge is power. We love to share it.

News related to Mono products, services and latest developments in our community.

mzilic

Using LinkedIn API from ASP.NET and MonoX

03/05/2012Categories: MonoX

Intro

Quite a few projects I worked on recently required some form of LinkedIn integration. There were different requirements, from posting status updates to importing users profiles to an extended MonoX profile. As any developer would do, I headed over to LinkedIn's Libraries and Tools page. Since we write our applications in C#, I had several libraries to choose from. After extensive research I decided to go with LinkedIn Developer Toolkit.

LinkedIn's API uses OAuth protocol for authentication. This allows the application to act (either permanently or temporarily) on behalf of the user without the need for the user to give out his username and password. Information can be retrieved using REST HTTP requests; returned data is in the XML format.

Why choose LinkedIn Developer Toolkit?

Most of the available libraries only allow you to perform basic authentication and to retrieve access tokens, but do not have the inbuilt functionality to post status updates or fetch user data. So instead of having to reinvent the wheel I decided immediately to select the LinkedIn Developer Toolkit. Currently the toolkit does not support Company Status Updates.
Please note that the toolkit uses DotNetOpenAuth project for authentication.

Registering new LinkedIn application

Head over to LinkedIn's developer site and login using your LinkedIn account.
From the APIs menu select API Overview menu option.
1
Click on the Register button.
2
On the List of Applications screen click on Add new application button.
3
On the Add New Application screen enter details about your application. Once you are done click on the Add Application button and copy the API key and the Secret Key. Make sure not to give these keys to anyone.

Implementing IConsumerTokenManager

We will need to make our own implementation of IConsumerTokenManager interface. For the demonstration purposes I am storing the access tokens in the session. If you are developing a feature which requires temporary access to users' profile, storing the access token in the session is the way to go. However, if you are planning to develop a feature which requires permanent access you will need to store the access token in the database.

You should of course notify your users that you are storing their access tokens and enable them to remove these access tokens from your system at any time.
The TokenManager class:
public class TokenManager : IConsumerTokenManager
    {
        #region Constructor
        public TokenManager()
            : base()
        {
        }
 
        public TokenManager(string appKey, string appSecret)
        {
            ConsumerKey = appKey;
            ConsumerSecret = appSecret;
        }
        #endregion
 
        #region Properties
        private string _consumerKey = ApplicationSettings.LinkedInKey;
        public string ConsumerKey
        {
            get { return _consumerKey; }
            set { _consumerKey = value; }
        }
 
        private string _consumerSecret = ApplicationSettings.LinkedInSecretKey;
        public string ConsumerSecret
        {
            get { return _consumerSecret; }
            set { _consumerSecret = value; }
        }
        #endregion
 
        #region Methods
        public void ExpireRequestTokenAndStoreNewAccessToken(string consumerKey, string requestToken, string accessToken, string accessTokenSecret)
        {
            HttpContext.Current.Session["AccessToken"] = accessToken;
            HttpContext.Current.Session["AccessTokenSecret"] = accessTokenSecret;
        }
 
        public string GetTokenSecret(string token)
        {
            return HttpContext.Current.Session["AccessTokenSecret"] != null ? HttpContext.Current.Session["AccessTokenSecret"].ToString() : string.Empty;
        }
 
        public TokenType GetTokenType(string token)
        {
            throw new NotImplementedException();
        }
 
        public void StoreNewRequestToken(DotNetOpenAuth.OAuth.Messages.UnauthorizedTokenRequest request, DotNetOpenAuth.OAuth.Messages.ITokenSecretContainingMessage response)
        {
            HttpContext.Current.Session["AccessToken"] = response.Token;
            HttpContext.Current.Session["AccessTokenSecret"] = response.TokenSecret;
        }
        #endregion
    }

Retrieving Access Token

Before we can do anything, we need to ask the user for consent to access their account. To do that we need to build an authentication URL and redirect the user to the LinkedIn login page. To handle LinkedIn authentication and callbacks we use a separate page. We also need to have in mind that we need to differentiate the LinkedIn callbacks from authorization requests, so we need to append a query parameter to the LinkedIn callback URL. We will use that query parameter to differentiate betwen callback and authorization request.

Code required to build the authorization URL and to complete the authorization:
#region Properties
        private TokenManager _tokenManager = null;
        public TokenManager TokenManager
        {
            get
            {
                if (_tokenManager == null)
                {
                    _tokenManager = new TokenManager();
                }
                return _tokenManager;
            }
        }
 
        public WebOAuthAuthorization Authorization { get; set; }
 
        public bool IsLinkedInCallback
        {
            get
            {
                bool isCallback = false;
                if (Request.QueryString["isCallback"] != null)
                    bool.TryParse(Request.QueryString["isCallback"], out isCallback);
                return isCallback;
            }
        }
        #endregion
 
        #region Page events
        protected void Page_Load(object sender, EventArgs e)
        {
            try
            {
                if (!this.IsLinkedInCallback)
                {
                    // reset access tokens
                    HttpContext.Current.Session["AccessToken"] = string.Empty;
                    HttpContext.Current.Session["AccessTokenSecret"] = string.Empty;
                }
                string accessToken = IsLinkedInCallback && HttpContext.Current.Session["AccessToken"] != null ? HttpContext.Current.Session["AccessToken"].ToString() : string.Empty;
                this.Authorization = new WebOAuthAuthorization(this.TokenManager, accessToken);
                if (!IsLinkedInCallback)
                {
                    // append the query parameter
                    this.Authorization.BeginAuthorize(new Uri(Request.Url.AbsoluteUri.Append("isCallback", true)));
                    //this.Authorization.BeginAuthorize(new Uri(Request.Url.AbsoluteUri + "?isCallback=true"));
                }
                else
                {
                    // complete the authorization and fetch the access tokens
                    this.Authorization.CompleteAuthorize();
                    // redirect back to source page
                    Response.Redirect("/Default.aspx");
                }
            }
            catch (Exception ex)
            {
                log.Error(ex);
            }
        }
        #endregion

Posting a Status Update

Once we have access tokens we can begin doing something with the user account. Things are pretty much straightforward from here, you only need to pass on a few parameters to the LinkedIn Developer Toolkit and it will take care of the rest.

The code needed to post a status update:
if (HttpContext.Current.Session["AccessToken"] != null)
    {
        var authorization = new WebOAuthAuthorization(new TokenManager(), HttpContext.Current.Session["AccessToken"].ToString());
        LinkedInService service = new LinkedInService(authorization);
        service.CreateShare("My test comment", LinkedIn.ServiceEntities.VisibilityCode.ConnectionsOnly);
    }

Fetching User Profile

Let's see how you can fetch some of your own profile fields and your connections.

Sample code:
if (HttpContext.Current.Session["AccessToken"] != null)
    {
        var authorization = new WebOAuthAuthorization(new TokenManager(), HttpContext.Current.Session["AccessToken"].ToString());
        LinkedInService service = new LinkedInService(authorization);
        // fetch standard profile  
        List<ProfileField> fields = new List<ProfileField>();
        fields.Add(LinkedIn.ServiceEntities.ProfileField.FirstName);
        fields.Add(LinkedIn.ServiceEntities.ProfileField.LastName);
        fields.Add(LinkedIn.ServiceEntities.ProfileField.Connections);
        fields.Add(LinkedIn.ServiceEntities.ProfileField.Headline);
        var profile = service.GetCurrentUser(ProfileType.Standard, fields);
        if (profile != null)
        {
            string fullName = profile.Name;                   
            if (profile.Connections.Items != null && profile.Connections.Items.Count > 0)
            {
                foreach (var item in profile.Connections.Items)
                {
 
                }
            }
        }
    }

Conclusion

LinkedIn Developer Toolkit will save you a lot of time, as it allows easy and quick integration of LinkedIn functionality into your site. I highly recommend looking into an additional post on how to extend a MonoX profile if you're looking to import a lot of additional fields not available in the standard MonoX profile.
Rated 3.56, 18 vote(s). 
mzilic
The sample code is available as a part of this blog post near the bottom just above the tags.

Regards
By Ananta
Hello,
I just wanted to know how to list the groups followed by the user and how to post to one of those groups on behalf of the user. Kindly let me know.
Thanks.
mzilic
Hi,

Unfortunately LinkedIn recently updated their API guidelines and permissions so this blog post no longer applies to most of these scenarios. Please see on their announcement page: https://developer.linkedin.com/support/developer-program-transition

Regards
1 2 3