Working with SharePoint 2010 User Activity NewsFeed

26 במרץ 2011

I was recently tasked with creating an application that once used will add an entree to the user's activity feed.

The activity feed is a fun and social feature (one of many) of SharePoint 2010, and its purpose is to present a feed of actions that the user or his colleagues performed on the site.

You can see how the activity feed looks on the following screen shot, taken from my local SharePoint development environment:

Now hopefully that got you excited enough to read on ;)

We are going to build a simple web part that will add an entree to the user activity feed. The web part will contain a single text box and a button that once pressed will add the entree to the user's feed.

1) Open Visual Studio 2010, create a new Empty SharePoint Project with the name "ActivityFeedInteraction" and choose to deploy it as farm solution. 

2) Right click on the solution name, choose "Add" and then "New Item". Click on "Web Part" and name it "ActivityWebpart"

3) Right click on "References" and choose "Add Reference". Add the following 3 dlls to your solution:

  • Microsoft.Office.Server

  • Microsoft.Office.Server.UserProfiles

  • System.Web

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

As we can see there are plenty of
default activities that the user follows, and if we wish to tap in the user's
news feed we have to build a new activity for him to follow first. In our
solution we will create that activity once the feature that installs the web
part is activated.

In visual studio, expend the Features node, right click on "Feature1"
and choose "Add Event Receiver" as seen on the following screen shot:

5) Open Feature1.EventReceiver.cs and uncomment the FeatureActivated method.

6) Add the following code to the method:

UserProfileManager pm = new
UserProfileManager(SPServiceContext.Current);
UserProfile
currentUserProfile =
pm.GetUserProfile(SPContext.Current.Site.OpenWeb().CurrentUser.LoginName);
ActivityManager actMgr = new
ActivityManager(currentUserProfile);
ActivityType customActivityType = null;
ActivityApplication actApplication = null;
ActivityTemplate
customActTemplate = null;

Let's explain what we did here:
First we created a UserProfileManager object and passed the current SPService
context to it, then we created a UserProfile object of the currently logged in
user, then we created an ActivityManager object for the current user and
finally we created an empty ActivityType, ActivityApplication and
ActivityTemplate objects. We will use all of these later.

7) Add the following code right below the code you previously pasted:

if (actMgr.PrepareToAllowSchemaChanges())

{

}

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"
);


}

Before we go on with the creation of the activity we need to check if the user who install the feature have the required rights to create it. If he does – we go on with the creation, if not we write a message to SharePoint's log and quit. 

8) Now it's time to add the code for
creating the activity. First we create the activity application using the
following code (paste it inside the if statement):

if (actMgr.ActivityApplications["CustomActivity"]
== null)

{
    actApplication = actMgr.ActivityApplications.Create("CustomActivity");

    actApplication.Commit();

    actApplication.Refresh(false);

}

else

{

    actApplication = actMgr.ActivityApplications["CustomActivity"];

}

First we check if an activity application named CustomActivity exsist, if it doesn't – we create it, if it does – we initialize our actApplication object to it.

9) Now that we have our
ActivityApplication object ready, it's time to move on to the ActivityType. Paste
the following code right below the previous code blocks:

customActivityType = actApplication.ActivityTypes["MyCustomActivity"];

if (customActivityType == null)
{

    customActivityType = actApplication.ActivityTypes.Create("MyCustomActivity");

    customActivityType.ActivityTypeNameLocStringResourceFile = "CustomActivityResource";   
    customActivityType.ActivityTypeNameLocStringName = "ActivityName";

    customActivityType.IsPublished = true;
    customActivityType.IsConsolidated = true;

    customActivityType.AllowRollup = true;

    customActivityType.Commit();

    customActivityType.Refresh(false);

}

Like before, we first try to get our activity type from the ActivityApplication
activity types collection, if it comes back null that means it doesn't exists
and we move on to creating it.
There are 2 lines of code in this block that we need to draw attention to:

customActivityType.ActivityTypeNameLocStringResourceFile = "CustomActivityResource";

customActivityType.ActivityTypeNameLocStringName = "ActivityName";

The first lines set the activity type resource file name and the second set the name inside the resource file for the activity name.

You might be wondering what is this resource file we are talking about, so fear not! We are going to create it next. 

10) Right click on the solution name and choose "Add" and then "SharePoint Mapped Folders". You should see the following dialog box:

Click on "Resources" and then OK.

11) Right click on the newly created
"Resources" node in our solution and choose "Add" ->
"New Item". Find "Resource File" in the list of available
templates and name it CustomActivityResource (this is how we set ActivityTypeNameLocStringResourceFile in the previous step).

12) 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 from the previous
step) and give it a value of "My New Sweet Custom Activity!" This is the
name that will be shown on the newsfeed settings screen we saw in step 4. 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.

13) We are now done with the ActivityType object and we are moving on to creating the last object in our activity – the template. Paste the following code right below the closing
bracket for the last if statement: 

customActTemplate =
customActivityType.ActivityTemplates[ActivityTemplatesCollection.CreateKey(false)];

if (customActTemplate == null)
{

    customActTemplate = customActivityType.ActivityTemplates.Create(false);

    customActTemplate.TitleFormatLocStringResourceFile = "CustomActivityResource";

    customActTemplate.TitleFormatLocStringName = "Activity_Created";
   
customActTemplate.Commit();
    customActTemplate.Refresh(false);

}

Just like before, we check if the
template we need already exists, if it doesn't we create it. We then need to
provide a resource file that holds a string that will act as a template for the
user's news feed. (In our code this template is called Activity_Created).

14) Open the resource file we previously created (CustomActivityResource) and add a new row with the following info:

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

Think of the value text as the template for the activity. This template is how the
activity will show on the user's newsfeed. The template can use template
variables like {Publisher} and {Value} that will be replaced by data we provide
to the activity at run time. Other variables like {Link} or {Size} can also be
used if needed.

15) That's it! We are done with
creating the activity! At this point, your method should look like this:

public override void FeatureActivated(SPFeatureReceiverProperties
properties)
{

    UserProfileManager
pm = new
UserProfileManager(SPServiceContext.Current);
    UserProfile currentUserProfile =
pm.GetUserProfile(SPContext.Current.Site.OpenWeb().CurrentUser.LoginName);
    ActivityManager
actMgr = new
ActivityManager(currentUserProfile);
   
ActivityType customActivityType = null;
    ActivityApplication
actApplication = null;

    ActivityTemplate
customActTemplate = null;

    if (actMgr.PrepareToAllowSchemaChanges())
    {
        if
(actMgr.ActivityApplications["CustomActivity"] == null)
        {
            actApplication =
actMgr.ActivityApplications.Create("CustomActivity");
            actApplication.Commit();
            actApplication.Refresh(false);
        }
        else

        {
            actApplication =
actMgr.ActivityApplications["CustomActivity"];
        }

        customActivityType = actApplication.ActivityTypes["MyCustomActivity"];

       
        if (customActivityType == null)

        {

            customActivityType = actApplication.ActivityTypes.Create("MyCustomActivity");

            customActivityType.ActivityTypeNameLocStringName = "ActivityName";

            customActivityType.ActivityTypeNameLocStringResourceFile = "CustomActivityResource";

            customActivityType.IsPublished = true;

            customActivityType.IsConsolidated = true;

            customActivityType.AllowRollup = true;

            customActivityType.Commit();

            customActivityType.Refresh(false);

        }

        customActTemplate = customActivityType.ActivityTemplates[ActivityTemplatesCollection.CreateKey(false)];

        if (customActTemplate == null)
        {
            customActTemplate = customActivityType.ActivityTemplates.Create(false);
            customActTemplate.TitleFormatLocStringResourceFile = "CustomActivityResource";
            customActTemplate.TitleFormatLocStringName = "Activity_Created";
            customActTemplate.Commit();
            customActTemplate.Refresh(false);
        }
    }
    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"
);
    }
}

16) Now that we have an activity let's make use of it! Open "ActivityWebPart" node and double click "ActivityWebpart.cs".

17) Add the following private variables:

private TextBox
_tbActivity;

private Label
_lblActivity,_lblInfo;
private Button
_btnActivity;

 18) Add the following code to the CreateChildControl method:

_lblActivity = new Label() { Text = "Activity
Text "
};

this.Controls.Add(_lblActivity);
_tbActivity = new TextBox();

this
.Controls.Add(_tbActivity);

this
.Controls.Add(new
Literal() { Text = "<br/>"
});

_btnActivity = new Button();

_btnActivity.Text = "Send
Activity"
;
_btnActivity.Click += new EventHandler(_btnActivity_Click);
this
.Controls.Add(_btnActivity);

this
.Controls.Add(new
Literal() { Text = "<br/>"
});

_lblInfo = new Label()
{ Visible=false };

this
.Controls.Add(_lblInfo);

19) Add the following method below
CreateChildControl:

void _btnActivity_Click(object
sender, EventArgs e)

{
    UserProfileManager
pm = new
UserProfileManager(SPServiceContext.GetContext(SPContext.Current.Site));

    UserProfile
currentUserProfile =
pm.GetUserProfile(SPContext.Current.Web.CurrentUser.LoginName);

    ActivityManager
actMgr = new
ActivityManager(currentUserProfile);

    try
    {

        long
aId = actMgr.ActivityApplications["CustomActivity"].ActivityTypes["MyCustomActivity"].ActivityTypeId;

        if (aId != 0)
        {

            CreateEvent(_tbActivity.Text, aId, currentUserProfile, actMgr);
            _lblInfo.Text = "Activity created
successfully!"
;

        }

        else

            _lblInfo.Text = "No Activity
Found!"
;

            
             _lblInfo.Visible = true;

    }
    catch (Exception
ex)

    {

        SPDiagnosticsService
.Local.WriteTrace(0,
new SPDiagnosticsCategory("Custom Activity Creator", TraceSeverity.High, EventSeverity.Error),
TraceSeverity.High,
ex.Message,ex.StackTrace);

    }

}

Once the button is clicked the
method gets the current user profile from the UserProfileManager object, and
then gets the activity id from the activity we have created in the feature
activated method. If we get an id we move on to the CreateEvent method which we
will build in the next step, but if no id is returned the method changes the
text on the info label to "No Activity Found" and quits.

20) Now let's add the final peace of the puzzle: the CreateEvent method. Add the
following code right below the closing bracket for _btnActivity_Click method

private void CreateEvent(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();

}

 

This method sets the publisher for
the method (the person who initiated it), then creates 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!

21) Time to test our solution. Click on the solution name and in the properties window change "Active Deployment" to "No Activation". Right click on the solution name and click Deploy.

22) Go to the site you deployed the
solution to; click "Site Actions" and "Site Settings".
Click on "Site Collection Features" and activate
"ActivityFeedInteraction Feature1"

23) Go to your "My Site" and click "Newsfeed Settings". You should
see our new activity is there and waiting for action!

24) Go back to your site, and add the "ActivityWebPart" web part to a page of your choice.

25) Type something in the text box and click "Send Activity".

26) If all went well, you should see on your "My Profile" page a new entree for your activity which was based on the template we supplied earlier! The following screenshot shows an example:

That's it! We have created a new
custom activity and a web part that accompany it in order to add events to a
user's newsfeed.

I hope this post helped you understand how to use the activity feed, one of the best social features of SharePoint 2010.

If you want to download the final project then go right ahead and click here.

Please feel free to contact me over twitter or using the contact me form here if you run into any issues or questions. 


הוסף תגובה
facebook linkedin twitter email

כתיבת תגובה

האימייל לא יוצג באתר. (*) שדות חובה מסומנים

9 תגובות

  1. FSikorski21 ביוני 2011 ב 20:06

    Hey Johnny, great walk through. I am trying to do create a custom news feed item from a SharePoint workflow instead of a webPart. Your code above works fine when it is executed from the browser, but when in the workflow activity I am getting a permissions error to the actMgr.ActivityApplications. It says the currentUserProfile needs to be an Administrator of the User Profiles, which it is. The code on the Feature activate works, but not in the workflow activity. I was wondering if you have any suggestions on why this might be happening. Thanks.

    להגיב
  2. Neo28 בספטמבר 2011 ב 19:15

    Hey Johnny, great job ! I have a question. What ever I post through the webpart appears on my recent activities but not on my colleagues newsfeed. Could you please tell me how I can make it work like the note board? What ever I post on my note board not only appears on my recent activities but also on my colleagues newsfeed.

    להגיב
  3. Jaimin18 בינואר 2012 ב 10:58

    Very much helpful. Thanks a bunch!

    להגיב
  4. jobin19 בינואר 2012 ב 13:27

    Hi Johnny.. great article . when i activate the feature from  "Site Collection Features" its showing that "An unexpected error has occurred.Troubleshoot issues with Microsoft SharePoint Foundation.

    Correlation ID: 133c9e82-86a3-448f-b54c-036e98f1cf2b" No Error message.. how can i find the error … plz HELP :)

    להגיב
  5. johnnyt27 בינואר 2012 ב 11:44

    Hey Jobin,
    You need to take a look at the logs (located in the 14 folder under Logs) and find the correlation id to get the full details of the error…

    להגיב
  6. Anil Kuchi9 באפריל 2012 ב 21:36

    Hi Johnny

    Can we disable some of the activity news feed using client object model .I want to hide some of the activities .Is there a way of achieving it using client object model

    להגיב
  7. Srikanth20 ביוני 2012 ב 17:52

    Hi Johnny,

    I recieve an error at
    "ActivityManager actMgr = new ActivityManager(currentUserProfile);"

    Error Message : "No mapping between account names and security IDs was done"

    Do you have any idea..

    להגיב
  8. Srikanth21 ביוני 2012 ב 12:42

    I have same problem which Neo mentions,can someone give a resolution.

    Issue – "Hey Johnny, great job ! I have a question. What ever I post through the webpart appears on my recent activities but not on my colleagues newsfeed. Could you please tell me how I can make it work like the note board? What ever I post on my note board not only appears on my recent activities but also on my colleagues newsfeed."

    להגיב
  9. Akshay27 באוגוסט 2012 ב 15:45

    Hi.

    Thanks a lot for the post. It was of great help.

    i had a doubt. I have created my own custom activity type which has the following template :

    {Publisher} has joined {Link} group.

    But i wanted a picture placeholder next to the {Link} placeholder. i.e {Publisher} has joined {Image}{link} group. Is there a place holder called {image} or {picture} else how do i do it?

    להגיב