Friday 8 July 2016

3 Ways of Accessing User Profile Properties in SharePoint 2013.


     Hi All, last week got a job of "Performance Tuning"  to the existing SharePoint Application. Its basically a "Data Service Layer", which uses, the Microsoft.SharePoint.dll to access the SharePoint list & document library and provides a web response to the other applications. While checking the code, found the usage of the heavy object UserProfileManager. ???  
Always remember this quote., while using Objects @ Extra Cost. 

       "Don't Force Yourself To Fit In, Where You Don't Belong"

This one will be applicable for your objects too. Use right objects under right context. 
In this scenario., for fetching of the 3 properties, they were accessing the complex UserProfileManager object. And that too, inside the responsive service layer, as this service response is needed red hot by the UI. Can't wait for recruit the manager, cook & Serve. So what's the alternative of accessing the user info, from SharePoint. Here they are: 

1) Access via UserInformation List (_catalogs/users.aspx) – Good

using(SPSite siteObj = new SPSite("site_url"); 
{ 
    SPWeb webObj = siteObj.OpenWeb(); 
    SPList userInformationList = webObj.SiteUserInfoList;  
   SPListItemCollection InformationList = userInformationList.Items; 
    foreach(SPListItem props in InformationLIst) 
    { 
       var UserObj = new{ ID =  props["ID"], 
                                           Email=props["EmailID"], 
                                           BirthDay=props["Birthday"]}; 
     } 
} 

  • Faster – If the user information, is to be fetched from the particular site, or group. 
  • We don't have control., whether the sync is happened for the edited profiles. 

2) Access via Search Service Application – Bad 

using Microsoft.Office.Server.Search.Administration; 
using Microsoft.Office.Server.Search.Query; 
                   var keywordQuery = new KeywordQuery(spSite) 
                    { 
                        QueryText = queryText, 
                        KeywordInclusion = KeywordInclusion.AllKeywords, 
                    }; 
                    keywordQuery.SelectProperties.Add("UserProfile_GUID"); 
                    keywordQuery.SelectProperties.Add("ID"); 
                    keywordQuery.SelectProperties.Add("EmailID"); 
                    keywordQuery.SelectProperties.Add("Birthday"); 
                    keywordQuery.RowLimit = 500; 
                    keywordQuery.TrimDuplicates = false; 
                    keywordQuery.SourceId = new Guid("B09A7990-05EA-4AF9-81EF-EDFAB16C4E31"); // to access user profile data store.
                    SearchExecutor searchExecutor = new SearchExecutor(); 
                    ResultTableCollection rt = searchExecutor.ExecuteQuery(keywordQuery); 
                    var tab = rt.Filter("TableType", KnownTableTypes.RelevantResults); 
                    var result = tab.FirstOrDefault(); 
                    DT = result.Table; 

  • Quite Fast.  
  • WorkAround Approach. Like accessing User Service Application's properties, need to take care about Search Service Application. Requires additional dlls, mapped in your code. 
  • Horrible to handle the custom properties, need to map them as Managed Properties in the Search Service Application setup. 

3) UserProfileManager - Ugly

  SPServiceContext context = SPServiceContext.GetContext(spSite); 
  UserProfileManager profileManager = new UserProfileManager(context); 
  var profile = profileManager.GetUserProfile(Convert.ToString(row["AccountName"])); 
 var UserObject = new {  ID =  props ["ID"], Email=props["EmailID"], BirthDay=props["Birthday"]}; 

  • Good to use, for the back end ops / offline apps, say, if you're building a birthday app, which triggers B'day emails, @ Mid-Night every day.  


Note: Have discussed here are only the approaches, of the accessing user profile properties, using Server Object Model. CSOM, JSOM & other /api/_ REST approaches of calling are not-applicable :P 

Happy Coding :)