How to: Add Activities to be displayed under the Recent Activity Webpart in My Site for User Profiles

 

I was recently working on a requirement where the Customer Wanted to show the Blogging activity of a User in any SharePoint site to appear in the Recent Activity WebPart in My Profile page of My Site.

Activity feeds are streams of social networking activities in Microsoft SharePoint Server 2010 that are generated, tracked, and displayed, both to the users who have generated the events and to colleagues who choose to follow the activities of other users.

This is how it looks in the following Screen Shot of My Profile in My Site. Check the Recent Activities in the picture where it shows the Comments posted in a post. (Just the basic text)

clip_image002[6]

The activity feed is based upon activities the user chooses to follow on his "Newsfeed Settings" screen:

clip_image004[6]

Now, to describe how to achieve this:

1. First we need to create a new ActivityApplication under the Activity Manager for the farm

2. We need to create a new ActivityType under the new Activity Application and create an Activity Template for the Type that would be used to display in the Recent Activities in the Profile page for a user in My Site.

Let’s start by creating the Activity application and the Type.

We will create a Farm scoped feature to add the Activity Application and the Type.

1. Open Visual Studio 2010 and create a new project of type “Empty SharePoint Project”

2. Add a new feature and change the name to what you would like it to be called

3. Change the “Scope” of the feature to “Farm”

4. Add the references to the following dll in the code

a. Microsoft.Office.Server

b. Microsoft.Office.Server.UserProfiles

5. Right Click the feature and add an Event receiver to the feature

6. In the FeatureActivated event handler, add the code to create a new Activity Application and register a new Type and the corresponding templates

a. he sample code to register a new Activity Application and Type is as

  public override void FeatureActivated(SPFeatureReceiverProperties properties)
         {
             try
             {
                 string _activityApplicationName = "MyCustomActivityApp";
                 string _activityTypeName = "MyCustomActivityType";
 
                 UserProfileManager _userProfileManager = new UserProfileManager(SPServiceContext.Current);
                 UserProfile _currentUserProfile = _userProfileManager.GetUserProfile(true);
                 ActivityManager _activityManager = new ActivityManager(_currentUserProfile, SPServiceContext.Current);
 
                 ActivityType _activityType = null;
                 ActivityApplication _activityApplication = null;
                 ActivityTemplate _customActTemplate = null;
                 
                 //Check if the User activating the feature has admin rights on the Activity Manager Schema
                 if (_activityManager.PrepareToAllowSchemaChanges())
                 {
                     _activityApplication= _activityManager.ActivityApplications[_activityApplicationName] ;
                     //If not found create
                     if (_activityApplication == null)
                     {
                         _activityApplication = _activityManager.ActivityApplications.Create(_activityApplicationName);
                         _activityApplication.Commit();
                         _activityApplication.Refresh(false);
                     }
                    
                     //Create the Activity Tyep if not found
                     _activityType = _activityApplication.ActivityTypes[_activityTypeName];
 
                     if (_activityType == null)
                     {
                         _activityType = _activityApplication.ActivityTypes.Create(_activityTypeName);
                         _activityType.ActivityTypeNameLocStringResourceFile = "CustomActivityResource"; 
                         _activityType.ActivityTypeNameLocStringName = "ActivityName";                        
                         _activityType.IsPublished = true;
                         _activityType.IsConsolidated = true;
                         _activityType.AllowRollup = true;
                         _activityType.Commit();
                         _activityType.Refresh(false);
                     }
 
                     //Create the Activity Template if not found
                     _customActTemplate = _activityType.ActivityTemplates[ActivityTemplatesCollection.CreateKey(false)];
 
                     if (_customActTemplate == null)
                     {
                         _customActTemplate = _activityType.ActivityTemplates.Create(false);
                         _customActTemplate.TitleFormatLocStringResourceFile = "CustomActivityResource";
                         _customActTemplate.TitleFormatLocStringName = "Activity_Created";
                         _customActTemplate.Commit();
                         _customActTemplate.Refresh(false);
                     }
                 }
                 // The user activating the feature does not have permissions on the User Profile Service
                 else
                 {
                     SPDiagnosticsService.Local.WriteTrace(0, new SPDiagnosticsCategory("Custom Activity Creator", TraceSeverity.High, EventSeverity.Error),
                         TraceSeverity.High, string.Format("The user {0} does not have the administrator rights on the User Profile service",
                         SPContext.Current.Site.OpenWeb().CurrentUser.LoginName), "");
                     throw new Exception("The user dosent have the required permissions for this action");
                 }
 
             }
             catch (Exception ex)
             {
                 SPDiagnosticsService.Local.WriteTrace(0, new SPDiagnosticsCategory("Custom Activity Creator", TraceSeverity.Verbose, EventSeverity.Information),
                     TraceSeverity.Unexpected, ex.Message + "\n" + ex.StackTrace, null);
 
                 throw;
             }
 
         }

If you look at the following code lines, you will find that it is referring to a Resource file and key value in the file

 _activityType.ActivityTypeNameLocStringResourceFile = "CustomActivityResource"; 
 _activityType.ActivityTypeNameLocStringName = "ActivityName"; 
 
 _customActTemplate.TitleFormatLocStringResourceFile = "CustomActivityResource";
 _customActTemplate.TitleFormatLocStringName = "Activity_Created";

7. Right click on the solution name and choose “Add” and then “SharePoint Mapped Folders”. You should see the following dialog box:

8.

clip_image006[6]

Click on Resources and “OK” to add the mapped folder to the project.

9. Right click on the newly created “Resources” folder and choose “Add” -> “New Item”. Find “Resource File” in the list of available templates and name it give the same name you gave in the code “CustomActivityResource” in the above case

10. Once the file is created, you will automatically be brought to the file editing screen. Replace “String1” with “ActivityName” (You’ve probably guessed that’s the same name as ActivityTypeNameLocStringName setting in the code) and give it a value of “My Custom Activity” This is the name that will be shown on the newsfeed settings screen we saw earlier in the screen shots at the beginning. You can add additional resource files in different languages and depending on the user’s language settings SharePoint will use the appropriate resource file for the user’s language.

11. Similarly, add a new row to be used as the ActivityTemplate with the following info:

Name: “Activity_Created”

Value: {Publisher} wrote {Value} on the wall using a custom activity!

We just finished the code for registering a new Activity Application and Types to the farm.

At the time of writing there is a missing API implementation for the removal of ActivityApplication. The API throws a ‘NotImplementedException’. So, if you try to remove the Custom Activity Application in FeatureDeactivating event handler, it will not work.

Now we will look into, how to add feed to the activity and to display it in the “Recent Activity” WebPart under the My Profile page for the user. In the original project I created a timer job to get all the new comments that had been posted by a user and then publish those activities in the Timer Job. However, for the sake of simplicity, we will do this in a Web Part here to push an activity to appear under the user’s newsfeed.

To create the WebPart, please follow the steps below:

1. In the above project, Right Click the project and Select ”Add” -> “New Item”.

2. Under the SharePoint 2010 Installed templates, select Web Part, change the name and click on “Add”.

3. It will take you to the CreateChildControls() method of the WebPart in the code.

4. If a new feature is not added to the project, then add a new feature to the project by right click on the Features folder and selecting “Add feature”. Set the scope of the feature to “Site”.

5. Add the WebPart as an item in the feature by opening the feature viewer in Visual Studio ( double-click on the new feature file added )

6. Add the following code to the WebPart .cs file.

 

 protected override void CreateChildControls()
         {
             _lblActivityData = new Label() { Text = "Enter the activity text " };
             this.Controls.Add(_lblActivityData);
             
             _txtActivityData = new TextBox();
             this.Controls.Add(_txtActivityData);
             
             this.Controls.Add(new Literal() { Text = "<br/>" });
             
             _btnSubmit = new Button();
             _btnSubmit.Text = "Submit";
             _btnSubmit.Click += new EventHandler(this._btnSubmit_Click);
             this.Controls.Add(_btnSubmit);
             
             this.Controls.Add(new Literal() { Text = "<br/>" });
             
             _lblStatus = new Label() { Visible = false };
             this.Controls.Add(_lblStatus);
         }
 
         protected void _btnSubmit_Click(object sender, EventArgs e)
         {
             UserProfileManager _userProfileManager = new UserProfileManager(SPServiceContext.GetContext(SPContext.Current.Site));
             UserProfile _currentUserProfile = _userProfileManager.GetUserProfile(SPContext.Current.Web.CurrentUser.LoginName);
             ActivityManager _activityManager = new ActivityManager(_currentUserProfile);
 
             try
             {
                 long _activityTypeId = _activityManager.ActivityApplications["CustomActivity"].ActivityTypes["MyCustomActivity"].ActivityTypeId;
                 if (_activityTypeId != 0)
                 {
                     this.PublishEvent(_txtActivityData.Text, _activityTypeId, _currentUserProfile, _activityManager);
                     _lblStatus.Text = "Activity published successfully!";
                 }
                 else
                 {
                     _lblStatus.Text = "Custom Activity Type not Found!";
                 }
 
                 _lblStatus.Visible = true;
             }
             catch (Exception ex)
             {
                 SPDiagnosticsService.Local.WriteTrace(0, new SPDiagnosticsCategory("Custom Activity Creator", TraceSeverity.High, EventSeverity.Error), TraceSeverity.High, ex.Message, ex.StackTrace);
             }
         }
 
 private void PublishEvent(string text, long aId, UserProfile currentUserProfile, ActivityManager actMgr)
         {
             Entity publisher = new MinimalPerson(currentUserProfile).CreateEntity(actMgr);
             ActivityEvent activityEvent = ActivityEvent.CreateActivityEvent(actMgr, aId, publisher, publisher);
             activityEvent.Name = "MyCustomActivity";
             activityEvent.ItemPrivacy = (int)Privacy.Public;
             activityEvent.Owner = publisher;
             activityEvent.Publisher = publisher;
             activityEvent.Value = text;
             activityEvent.Commit();
         }

7. The logic to publish the custom activity is put in the PublishEvent() method.

8. In this method we set the publisher for the method (the person who initiated it), then create an ActivityEvent object which will hold all the information about the event, setting its privacy, owner and publisher (in our example the owner and publisher are the same user, but if you want to publish events to other users, such as the current user colleagues - you will set different users in these properties) and finally we set the value property (which is what the {Value} template placeholder will use for rendering). Once we execute the Commit method, the event will show in the newsfeed!

Now is the time to test the solution.

Once the solution has been deployed (you can use Visual Studio’s deployment option – by right clicking on the project and select “Deploy” option or using stsadm command too), the farm feature would get activated automatically. Activate the Site Collection feature in a Root site by going to “Site Actions” -> “Site Settings” -> “Site Collection Features” and selecting the feature to activate.

Once the feature is activated, the webpart would be provisioned in the Gallery and can be used in the site.

Create a test page in the site using the “More Options” available under “Site Actions”. Add the Webpart ( can be found under the Custom group ). Add the text you wanted to be displayed/published as an activity on your recent activity and click on the submit button. Now go to your Profile by selecting My Profile in the welcome control on the top right of the page where your name is displayed. Check the recent activities that are displayed. You should see the activity published there.

If all the steps above have been followed religiously, the only thing that needs to be checked are the “User Profile Activity Feed” Timer jobs.

I have attached the sample code project also to this blog in case you want to refer.

ActivityFeed.zip