Click here to Skip to main content
15,886,724 members
Articles / Programming Languages / C#

LinkedIn User Groups, Posts, and Comments Desktop Application

Rate me:
Please Sign up or sign in to vote.
4.86/5 (15 votes)
15 Dec 2014CPOL3 min read 26.7K   14   11
A Bare-Bones Series Article

Source Code

The source code is now on GitHub.

Image 1

Introduction

I've been exploring the LinkedIn.NET library (Nuget here, Source Forge here) because, quite frankly, I find most web-based applications klunky and LinkedIn's user group forum web design is no exception.  What I present in this article leverages LinkedIn.NET to provide basic viewing of groups, posts within groups, comments within posts, and to add your own comments.  As primitive as it is, I find it much more usable than the web-based UI!

The UI

The UI consists of three panels:

  • A tree which shows the hierarchy of groups, posts, and comments
  • Information about the group, post, or comment.
  • An area for you to enter a comment to a post.

Code Walk-Through

The most interesting part of the code is the use of Task.Run and async/await.  Rather than using LinkedIn.NET's asynchronous calls, which require implementing a callback routine, I opted to use the synchronous version and wrap them in Task.Run calls.  This makes updating the UI a lot simpler!

Initialization

The application expects a linkedin.config file, with the following format:

  • line 1: your consumer key
  • line 2: our consumer secret

These are obtained from LinkedIn's developer site - in the Documentation menu, select "Getting Started."  The first two lines of the config file must be set with your "API Key" and "Secret Key".

Authentication

Image 2

Image 3

Your authorization web page will display YOUR name, not mine.

The access token, once obtained, is stored in the third line (I know, not very secure!)  The access token is obtain only through OAuth redirection, which makes the process rather klunky.  The LinkedIn.NET demo code has an interesting solution -- create a web browser with the OAuth URL and a redirect URI, then intercept the redirect in the browser control to obtain the access token. 

Image 4 

  • The redirect URL used in the application must match the redirect URL you specified when registering for the API key.
  • Similarly, the "State" value must match what you specified when registering for the API key as well.
// The code in this method is heavily borrowed from the LinkedIn.NET's LNTest "authenticate" method (DlgExample.cs)
protected void Authenticate()
{
  if (linkedInClient != null)
  {
    var options = new LinkedInAuthorizationOptions
    {
      RedirectUrl = REDIRECT_URL,
      Permissions = LinkedInPermissions.Connections | LinkedInPermissions.ContactsInfo |
      LinkedInPermissions.EmailAddress | LinkedInPermissions.FullProfile |
      LinkedInPermissions.GroupDiscussions | LinkedInPermissions.Messages |
      LinkedInPermissions.Updates,
      State = STATE
    };

    //create new instance of authorization dialog using authorization link built by _Client
    var dlgAuth = new DlgAuthorization(linkedInClient.GetAuthorizationUrl(options));

    if (dlgAuth.ShowDialog(this) == DialogResult.OK)
    {
      //get access token using authorization code received
      var response = linkedInClient.GetAccessToken(dlgAuth.AuthorizationCode, REDIRECT_URL);

      if (response.Result != null && response.Status == LinkedInResponseStatus.OK)
      {
        accessToken = response.Result.AccessToken;
        SaveConfiguration();
      }
    }
    else
    {
      //show error information
      MessageBox.Show(dlgAuth.OauthErrorDescription, dlgAuth.OauthError);
    }
  }
}

Once authenticated, the config file is saved with the access token.

Loading Groups

Using the LinkedIn.NET API is very simple.  First we load groups to which the user (you) belong to:

protected async void LoadGroups()
{
  if (haveAccessToken)
  {
    tvGroups.Nodes.Clear();
    tvGroups.Nodes.Add("Loading...");
    LinkedInGetGroupOptions options = new LinkedInGetGroupOptions();
    options.GroupOptions.SelectAll();

    LinkedInResponse<IEnumerable<LinkedInGroup>> result = await Task.Run(() => linkedInClient.GetMemberGroups(options));

    if (result.Result != null && result.Status == LinkedInResponseStatus.OK)
    {
      ShowMemberGroups(result);
    }  
    else
    {
      ReRun(result.Status, result.Message);
    }
  }
}

And add them to the tree:

protected void ShowMemberGroups(LinkedInResponse<IEnumerable<LinkedInGroup>> result)
{
  tvGroups.Nodes.Clear();

  foreach (LinkedInGroup group in result.Result)
  {
    TreeNode node = tvGroups.Nodes.Add(group.Name);
    node.Tag = group;
  }
}

Loading Group Posts

When the user double-clicks on a group, the posts are loaded for that group:

protected async void LoadPostsForGroup(TreeNode node, LinkedInGroup group)
{
  LinkedInGetGroupPostsOptions options = new LinkedInGetGroupPostsOptions();
  options.PostOptions.SelectAll();
  options.GroupId = group.Id;
  ShowLoading(node);

  await Task.Run(() => group.LoadPosts(options));

  ShowGroupPosts(node, group);
  node.ExpandAll();
}

protected void ShowGroupPosts(TreeNode node, LinkedInGroup group)
{
  node.Nodes.Clear();

  foreach (LinkedInGroupPost post in group.Posts)
  {
    TreeNode childNode = node.Nodes.Add(post.Title);
    childNode.Tag = post;
  }
}

Loading Post Comments

Finally, when the user double-clicks on a post, the comments are loaded:

protected async void LoadCommentsForPost(TreeNode node, LinkedInGroupPost post)
{
  LinkedInGetGroupPostCommentsOptions options = new LinkedInGetGroupPostCommentsOptions();
  options.CommentOptions.SelectAll();
  options.PostId = post.Id;
  ShowLoading(node);

  await Task.Run(() => post.LoadComments(options));

  ShowGroupPostComments(node, post);
  node.ExpandAll();
}

protected void ShowGroupPostComments(TreeNode node, LinkedInGroupPost post)
{
  node.Nodes.Clear();

  foreach (LinkedInGroupComment comment in post.Comments)
  {
    TreeNode childNode = node.Nodes.Add(comment.Text.LimitLength(64));
    childNode.Tag = comment;
  }
}

Adding a Comment

Comments are added to posts, so once a post has been selected, you are able to add a comment to that post.  Here, in addition to posting the comment, we manually add the comment to tree:

protected void AddComment(LinkedInGroupPost post, string comment)
{
  post.Comment(comment);

  // After posting the comment, add it to the post's comment collection, select it, and display the comment in the info box.
  tbComment.Text = "(posted)";
  TreeNode childNode = selectedPostNode.Nodes.Add(comment.LimitLength(64));
  tvGroups.SelectedNode = childNode;
  tbInfo.Text = comment;
}

LinkedIn can be a bit slow in updating the post with your comment, so if you double-click on the post to refresh the comments but don't see your comment, be patient.

Also, be careful that you are posting to the correct group -- the currently selected post or the currently selected comment in a post determines the post.

Conclusion

There's a LOT of bells and whistles that could be added to this demo, but then it wouldn't be a "bare-bones" demo! 

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Architect Interacx
United States United States
Blog: https://marcclifton.wordpress.com/
Home Page: http://www.marcclifton.com
Research: http://www.higherorderprogramming.com/
GitHub: https://github.com/cliftonm

All my life I have been passionate about architecture / software design, as this is the cornerstone to a maintainable and extensible application. As such, I have enjoyed exploring some crazy ideas and discovering that they are not so crazy after all. I also love writing about my ideas and seeing the community response. As a consultant, I've enjoyed working in a wide range of industries such as aerospace, boatyard management, remote sensing, emergency services / data management, and casino operations. I've done a variety of pro-bono work non-profit organizations related to nature conservancy, drug recovery and women's health.

Comments and Discussions

 
QuestionThe remote server returned an error: (401) Unauthorize Pin
Member 110744298-Jan-15 1:52
Member 110744298-Jan-15 1:52 
AnswerRe: The remote server returned an error: (401) Unauthorize Pin
Marc Clifton8-Jan-15 2:20
mvaMarc Clifton8-Jan-15 2:20 
GeneralMy vote of 5 Pin
Humayun Kabir Mamun16-Dec-14 0:01
Humayun Kabir Mamun16-Dec-14 0:01 
QuestionLinkedInDesktopUI-noexe.zip appears to be missing Pin
BigTimber@home11-Dec-14 2:38
professionalBigTimber@home11-Dec-14 2:38 
AnswerRe: LinkedInDesktopUI-noexe.zip appears to be missing Pin
Marc Clifton11-Dec-14 2:47
mvaMarc Clifton11-Dec-14 2:47 
QuestionWell Done Marc Pin
Peter Shaw11-Dec-14 0:22
professionalPeter Shaw11-Dec-14 0:22 
AnswerRe: Well Done Marc Pin
Marc Clifton11-Dec-14 2:23
mvaMarc Clifton11-Dec-14 2:23 
Peter Shaw wrote:
makes a difference from how Lidnug has been archiving it's conversations so far


The whole history is there. It's fun reading through older stuff.

I also haven't explored LinkedIn.NET's post/comment filtering capability -- I know LinkedIn itself supports filtering, just haven't figured it out using the wrapper. Can't be that hard, an it???

Thanks for response!

Marc

GeneralRe: Well Done Marc Pin
Peter Shaw14-Dec-14 1:45
professionalPeter Shaw14-Dec-14 1:45 
QuestionFew bugs Pin
fredatcodeproject10-Dec-14 23:01
professionalfredatcodeproject10-Dec-14 23:01 
AnswerRe: Few bugs Pin
Marc Clifton11-Dec-14 2:27
mvaMarc Clifton11-Dec-14 2:27 
GeneralRe: Few bugs Pin
fredatcodeproject11-Dec-14 5:28
professionalfredatcodeproject11-Dec-14 5:28 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.