Thursday, February 25, 2010

Creating SP2010 Social Comments programmatically for another user.

Technorati Tags: ,,

Recently I have seen people wanting to migrate user’s social comments or tags from custom SP 2007 solutions to SP2010 sites. Creating social comments programmatically requires the use of the new “Service Application Framework” and using the “User Profile Service Application”. The problem is how to create these comments with the appropriate user when doing this in bulk. You must use the Microsoft.Office.Server.SocialData.SocialCommentManager. This class takes a SPServiceContext object in its constructor. Now most SharePoint developers would expect that by creating a SPSite with the user’s SPUserToken and passing in this SPSite to the SPServiceContext.GetContext method that it would create an impersonated SPServiceContext that would generate a comment with that user’s name and id. Unfortunately, this is not the case. It seems that the “User Profile Service Application” relies on the HttpContext object to get user profile information to determine who is generating tags and comments.

So the requirement seems that you must create an HttpContext and add the impersonated user to the HttpContext. There are many problems with this. First it requires that you know the user’s password in order to impersonate and secondly it requires that you add that user to the list of users who can call the “User Profile Service Application”. Having to know the user’s password and some how pass  it to the code is worth the following small “hack”.  This “hack” uses reflection to change the WindowsIdentity’s name property. It is this property that is used to grab the user’s profile in order to label the comment.  So all you have to do is substitute the SPUser.LoginName for the WindowsIdentity.Name and all is taken care of. What is also nice is that this change only changes that instance of the WindowsIdentity, so you are not actually changing the current user’s name. Below is the code.

 

public static void CallServiceApplicationImpersonated()
      {          

          using (SPSite site = new SPSite("http://basesmc2008"))
          {
              using (SPWeb web = site.OpenWeb())
              {
                  SPUser user = web.EnsureUser("servername\\steve.curran");
                  web.AllowUnsafeUpdates = true;

                  HttpRequest request = new HttpRequest("", http://servername, "");

                  HttpContext.Current =
                      new HttpContext(request,
                          new HttpResponse(new StringWriter(CultureInfo.CurrentCulture)));

                  HttpContext.Current.Items["HttpHandlerSPWeb"] = web;

                  WindowsIdentity wi = WindowsIdentity.GetCurrent();

                  typeof(WindowsIdentity).
                      GetField("m_name", BindingFlags.NonPublic | BindingFlags.Instance)
                      .SetValue(wi, user.LoginName);

                  HttpContext.Current.User = new GenericPrincipal(wi, new string[0]);

                  WindowsIdentity wi2 = WindowsIdentity.GetCurrent();

                  SocialCommentManager socialCommentManager =
                      new SocialCommentManager(
                          SPServiceContext.GetContext(HttpContext.Current));

                  socialCommentManager.AddComment
                      (new Uri("http://basesmc2008/page.aspx"), "mycomment");

                  web.AllowUnsafeUpdates = false;
              }

          }

      }

2 comments:

anirudh gupta said...

Thanks for sharing this.

Used mostly your logic to add Activity Feed Event by non admin user.

http://mykbdump.blogspot.com/2010/08/create-activity-feed-event-by-non-admin.html

Anonymous said...

Thanx for sharing!

One thing,

SocialCommentManager socialCommentManager =
new SocialCommentManager(SPServiceContext.GetContext(HttpContext.Current));

When I run this I get a NullReferenceException...any idea of why this might be?

Post a Comment