Thursday, May 31, 2012

Configuring the User Profile Service in SharePoint 2010 {P3}
[working with user profile service Code level [vs 20101] - (how to get user detail , user properties and how to search users using user profile service)] 


With my previous posts [ P1 , P2 ] I have explained how to configure and Sync SharePoint User profile service with Active Directory and How to Map additional or Required field in UPS with AD attributes.


In this post I'm gonna explain and show how to work with our User profile service and do basic function in a programmatic way (Code Level). I'm gonna introduce there seperate function which help you to understand the way we need to deal with User Profile Service and the best practices specially when you deal with searching users.


Function No 1 : How to Search One User [most effective way]



Code:
using MicrosoftUserProfiles = Microsoft.Office.Server.UserProfiles;

        
        /// <summary>
        /// this will show one user detail
        /// </summary>
        /// <param name="site"></param>
        /// <param name="userId"></param>
        protected void showOneUser(SPSite site, string userId)
        {
            using (site)
            {
                LiteralControl lt = new LiteralControl();
                SPServiceContext context = SPServiceContext.GetContext(site);
                MicrosoftUserProfiles.UserProfileManager upm = new MicrosoftUserProfiles.UserProfileManager(context);
                //search one singel user using his accountname
                MicrosoftUserProfiles.UserProfile profile = upm.GetUserProfile(userId);
                String WorkEmail = profile[MicrosoftUserProfiles.PropertyConstants.WorkEmail].Value.ToString();
                String FirstName = profile[MicrosoftUserProfiles.PropertyConstants.FirstName].Value.ToString();
                String LastName = profile[MicrosoftUserProfiles.PropertyConstants.LastName].Value.ToString();

                lt.Text = "<br/><br/><b>WorkEmail :" + WorkEmail + "</b><br/><br/>";
                lt.Text += "<b>FirstName" + FirstName + "</b><br/>";
                lt.Text += "<b>LastName :" + LastName + "</b><br/>";
                lt.Text += "<b>ID :" + profile.ID + "</b><br/>";

                base.Controls.Add(lt);
            }
        }



Line by Line :


  1. using MicrosoftUserProfiles = Microsoft.Office.Server.UserProfiles;first you need to add Microsoft.Office.Server.UserProfiles.dll into reference. you can find it in following location "C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\14\ISAPI\Microsoft.Office.Server.UserProfiles.dll" then import it. 
  2. Create user profile service instance which, help to get user details. MicrosoftUserProfiles.UserProfileManager upm = new MicrosoftUserProfiles.UserProfileManager(context);
  3. Get user detail using GetUserProfile() method, it returns UserProfile object which hold all the properties which extract from UserProfile service.               MicrosoftUserProfiles.UserProfile profile = upm.GetUserProfile(userId);
  4. Best practice is not to user string hard coded property names to get user details, instead of that you can use   PropertyConstants for that as   MicrosoftUserProfiles.PropertyConstants .WorkEmail Likewise 



Function No 2 : Show all the existing properties and data for one user [you can see Error if that property has not been configured well. ]



Code:
        /// <summary>
        /// this is show propety collection and fill data against to that
        /// </summary>
        /// <param name="site"></param>
        /// <param name="userId"></param>
        protected void showPropertyCollection(SPSite site, string userId)
        {
            using (site)
            {
                LiteralControl lt = new LiteralControl();
                SPServiceContext context = SPServiceContext.GetContext(site);
                MicrosoftUserProfiles.UserProfileManager upm = new MicrosoftUserProfiles.UserProfileManager(context);
                MicrosoftUserProfiles.UserProfile profile = upm.GetUserProfile(userId);
                // get all properties (Name and Display name only for testing purpose)
                Microsoft.Office.Server.UserProfiles.PropertyCollection propColl = profile.ProfileManager.PropertiesWithSection;
                if (profile != null && propColl != null)
                {
                    foreach (MicrosoftUserProfiles.Property prop in propColl)
                    {
                        try
                        {
                            lt.Text += "<br/><br/><b>property Name : " + prop.Name + "</b><br/>";
                            lt.Text += "<br/><b>property DisplayName : " + prop.DisplayName + "</b><br/>";
                            lt.Text += "<b>proerpty Value : " + profile[prop.Name] != null ? profile[prop.Name].Value : "empty" + "</b><br/>";
                        }
                        catch (Exception)
                        {
                            lt.Text += "<b>Error : </b><br/>";
                        }
                    }
                }

                base.Controls.Add(lt);
            }

        }




Line by Line :


  1. Microsoft.Office.Server.UserProfiles.PropertyCollection propColl = profile.ProfileManager.PropertiesWithSection; Use to get all the User Profile service properties and assign them in to property collection object.





Function No 3 : Search Data through user profile service and Bind the results into a Grid with paging.



Code:
        /// <summary>
        /// will search through user profil and bind result into the grid
        /// </summary>
        /// <param name="site"></param>
        /// <param name="searchPattern"></param>
        protected void searchThroughGrid(SPSite site, string searchPattern)
        {
            using (site)
            {
                SPServiceContext context = SPServiceContext.GetContext(site);
                // get all user profiles into User Profile Manage Object
                MicrosoftUserProfiles.UserProfileManager upm = new MicrosoftUserProfiles.UserProfileManager(context);
                //Search through that with given key word using profile base this is vary cost effective and performance wise perfect
                MicrosoftUserProfiles.ProfileBase[] searchResults = upm.Search(searchPattern);

                //create SP Grid view object and fill required propeties
                profileGrid = new SPGridView();
                profileGrid.AutoGenerateColumns = false;
                profileGrid.EnableViewState = true;
                profileGrid.AllowPaging = true;
                // Propety collection Binder class is holding all the required propeties and
                //functions which we can user to bind the data into the grid
                pcb = new PropertyCollectionBinder();
                foreach (MicrosoftUserProfiles.ProfileBase profileTemp in searchResults)
                {
                    // this loop will execute only for result not for it will not itrate through all User
                    //Profile data set which taken by User Profile Manager
                    MicrosoftUserProfiles.UserProfile up = upm.GetUserProfile(profileTemp.ID);
                    // here I only user few propeties we can configure them with our requirements
                    pcb.AddProperty(up[MicrosoftUserProfiles.PropertyConstants.AccountName].Value as string, up[MicrosoftUserProfiles.PropertyConstants.FirstName].Value as                     string, up[MicrosoftUserProfiles.PropertyConstants.LastName].Value as string, up[MicrosoftUserProfiles.PropertyConstants.Department].Value as string, up[MicrosoftUserProfiles.PropertyConstants.WorkPhone].Value as string);

                }
                profileGrid.PageIndexChanging += new GridViewPageEventHandler(profileGrid_PageIndexChanging);
                Controls.Add(profileGrid);
                pcb.BindGrid(profileGrid);
                base.Controls.Add(profileGrid);
            }

        }


         /// <summary>
        /// pagination Event
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void profileGrid_PageIndexChanging(object sender, GridViewPageEventArgs e)
        {
            profileGrid.PageIndex = e.NewPageIndex;
            pcb.BindGrid(profileGrid);
        }



As I think this is the most important function, when we talk about user-profile programming sector. I have used different approach to search users and try to exceed the performance level and also reduce the resource usage. we can discuss it in Line by Line section.

Line by Line :
  1. but  MicrosoftUserProfiles.ProfileBase[] searchResults = upm.Search(searchPattern); One way to search user according to the given keyword is , to get all users and iterate one by one and check for correct user who match with search scenario as following.                                                                            foreach (UserProfile profile in profileManager)

  1. {
         /// Add search criteria
    
     }                                                                                                    but when you go with this approach. you'll find that it take long time and more processing resources specially if you are iterating more than 10,000 profiles and it could be 100,000 who knows :) .                                                                                                                                                but profile manage gives us a one efficient way to search user only through it's User ID.  so we cannot use it with different keywords.  that's why I use MicrosoftUserProfiles.ProfileBase[]  which can hold the profile base objects that taken from . search method. as follow  upm.Search(searchPattern);                                              
  2. then you can iterate profile base object which only holds only search results. but you need to keep one thing in you mind you don't have all the detail regarding one user in a MicrosoftUserProfiles.ProfileBase object, as you do in MicrosoftUserProfiles.UserProfile Object, but you can get User ID from Profile base object. so using following iteration pattern you can take required user details.                                                                                         foreach (MicrosoftUserProfiles.ProfileBase profileTemp in searchResults)                {                                                                                                         // this loop will execute only for result not for it will not itrate through all User                    //Profile data set which taken by User Profile Manager                                                                       MicrosoftUserProfiles.UserProfile up = upm.GetUserProfile(profileTemp.ID);






I have create separate class called PropertyCollectionBinder to bind Data and create SP grid view. 

Property binder Class : 

using System;
using System.Web;
using System.Web.UI;
using System.Data;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using Microsoft.SharePoint;
using MicrosoftUserProfiles = Microsoft.Office.Server.UserProfiles;
using Microsoft.Office.Server;
using Microsoft.SharePoint.WebControls;
using System.Runtime.InteropServices;
using System.Xml.Serialization;

namespace SearchWebPartTest
{
    public class PropertyCollectionBinder
    {
        protected DataTable PropertyCollection = new DataTable();
        protected DataView PropertyView = new DataView();
        protected SPGridView grid = new SPGridView();
        public PropertyCollectionBinder()
        {
            PropertyCollection.Columns.Add("AccountName", typeof(string));
            PropertyCollection.Columns.Add("FirstName", typeof(string));
            PropertyCollection.Columns.Add("LastName", typeof(string));
            PropertyCollection.Columns.Add("Department", typeof(string));
            PropertyCollection.Columns.Add("WorkPhone", typeof(string));
        }
        public void AddProperty(string AccountName, string FirstName, string LastName, string Department, string WorkPhone)
        {
            DataRow newRow = PropertyCollection.Rows.Add();
            newRow["AccountName"] = AccountName;
            newRow["FirstName"] = FirstName;
            newRow["LastName"] = LastName;
            newRow["Department"] = Department;
            newRow["WorkPhone"] = WorkPhone;
        }
        public void BindGrid(SPGridView grid)
        {
            BoundField fldAccountName = new BoundField();
            fldAccountName.HeaderText = "Name";
            fldAccountName.DataField = "AccountName";
            fldAccountName.HtmlEncode = false;
            grid.Columns.Add(fldAccountName);

            SPBoundField fldFirstName = new SPBoundField();
            fldFirstName.HeaderText = "First Name";
            fldFirstName.DataField = "FirstName";
            grid.Columns.Add(fldFirstName);

            SPBoundField fldLastName = new SPBoundField();
            fldLastName.HeaderText = "Last Name";
            fldLastName.DataField = "LastName";
            grid.Columns.Add(fldLastName);

            SPBoundField fldDepartment = new SPBoundField();
            fldDepartment.HeaderText = "Department";
            fldDepartment.DataField = "Department";
            grid.Columns.Add(fldDepartment);

            SPBoundField fldWorkPhone = new SPBoundField();
            fldWorkPhone.HeaderText = "Ext";
            fldWorkPhone.DataField = "WorkPhone";
            grid.Columns.Add(fldWorkPhone);

            //PropertyCollection.DefaultView.Sort = "WorkPhone asc";
            PropertyView = new DataView(PropertyCollection);
            grid.DataSource = PropertyView;
            grid.Width = 500;
            grid.EnableViewState = true;
            grid.PageSize = 10;
            grid.AllowPaging = true;
            grid.PagerTemplate = null;
            grid.AutoGenerateColumns = false;
            grid.DataBind();
        }


    }
  
}




Ex: when we search users who belongs to the “ENGRG SRVCS” .


 And when you search through First or Last Name “thilina”



ok That's It ... 
HAPPY CODING

Configuring the User Profile Service in SharePoint 2010 {P2}
[User Profile Service Property Map with Active Directory Attributes]


In my previous post I explain, what is call "User profile Service" in SharePoint and what are the advantages and disadvantages, and most importantly "how we can sync it with our Active Directory (AD) " . so I when i publish that post I got some feedback from some of my colleagues. and also they asked one question which I thought it's good to share with you through another post.  


How to map User profile properties with Active Directory attribute ?? Why we need to do that ??


Ok, Let's start with second question. before jump into the technical part. Why we need to map properties with AD attribute. Thing is imagine when you firstly configure and Sync AD with SharePoint user profile service. you can see many of field get map with AD profile attributes. but not all. so then we need to map them again. and sync it. to do that you don't need to delete all service instance and recreate it again. instead of that you can simply map them separately . and another reason is, imagine that you have introduce new attribute to the AD and you hav already Sync AD with User profile service then surely, that newly create attribute has not been mapped with UPS. to overcome these kind of situations you need to know how to map it.  


How To Do That ??



If we need to add more properties and map it with AD fields, so this section Explain the basic steps with required screen attachments.
First Go to Central Administration>Application Management>User Profile Service> then click on Manage User Properties under the People section. 

Then you will See all the fields which currently existing and what are the fields which already mapping with AD Fields.


If you need to add new property and Map it with AD field the click on New Property.


Then Fill the Required Fields. In drop down select the AD field which you need to Map with.




Then clicks on Add, then you can see the filed get mapped.

Once you click ok, You can see the new property got added and you can access it programmatically using its Name (not the display Name).

ok That's It ... 
HAPPY CODING

Sunday, May 13, 2012

Configuring the User Profile Service in SharePoint 2010 
[Sync with Active Directory (AD)]

One of the project which I was assign to asked to to build a web part which shows user details like Title,First Name,Last Name, Dep .. etc. Employee records or data should pull from the Active Directory (So what is this Active directory : Simply, Active Directory (AD) is a directory service created by Microsoft for Windows domain networks.)

To do that couple of approaches came on to the table.

  1. Directly Deal with AD and Get the Data we want by sending some kind of searching mechanism.
  2. Create Time Job and pull all the data from a Active directory and inject them in to a list then using that list we can achieve the task.
  3. Using Profile Service.   


First two options has couple of draw backs.

Option One : Directly deal with AD - sure we can do this but it's a kind of a slow process. and it might hit performance of the Application as well as AD it self. AD has not been designed to work as a efficient Data Base (it's purpose id different).

Option Two: Create Timer Job. - Yes we can do this also and it's a mature process than directly dealing with AD, but we might face some issue with "List View Threshold" Eg: Imagine we got about 7000 records for one searching, if List View Threshold is 5000 (Default) then we might get exception. And to overcome this we had to change the settings for the application (Read more [ How to Change the List View Threshold and Other Resource Throttling Settings]). and this is a little bit pain process and takes time. Even user need to add more properties for the list and map them with Current Ad attribute. then we had to change the things from code level and re run it again.

When you consider on Option Three:  Using User Profile Service, "Yes" it's more Reliable and customization is easy. The most happiest part is it's design to address similar kind of situations which we are talking.

How to Sync ?? 

Go to the Central Administration > Application Management (Left Panel) > Click on Manage Service Application.



Then Click on User Profile Service Application which you are going to sync with Active directory.



There you can see some details as following on the Right Corner . if you see some miner number under the Number of User Profiles, it means that this Service has not been synced with AD.

Profiles
Number of User Profiles
8
Number of User Properties
68
Number of Organization Profiles
1
Number of Organization Properties
15

Audiences
Number of Audiences
1
Uncompiled Audiences
0
Audience Compilation Status
Idle
Audience Compilation Schedule
Every Saturday at 01:00 AM
Last Compilation Time
Ended at 5/5/2012 1:00 AM

Profile Synchronization Settings
Profile Synchronization Status
Current Synchronization Stage
None(0)
Synchronization Schedule (Incremental)
Every day at 01:00 AM



Then Go to the ‘Configure Synchronization Connections’ and Try to add new connection by click on Add New Connection.


If you get error message saying User Profile Synchronizing  service not running Then we have to Up the service.




To Do that Go to the System Settings > Manage Service On Server.


The you will see that User Profile Synchronizing service is in Stop state.

Click on Start then you get following window, give the credential for that, and then click ok. 
Then You will see that service status is changing to “starting”.

Then you have to wait few minutes (it’ll take 5 – 10 min). Till it completed (Once it completed you see status as “Started”).


Then again go to the User Profile Service and click on Configure Synchronization Connections then click on Add New Connection (Now you can see New connection Adding Window will open up [coz service has stared ])


Then Fill Following fields Forest name, Account name, Password.
Onece it done click on Populate Cotainers button the it’ll reach the Active Directory and populate groups and categories.



You can select the categories or Groups which you need to sync (in here I checked domain which sync all the domain records)


Then clicks ok and it’ll take some time to adding the new connection.


Then go to the User Profile Service again and clicks on starts profile synchronization. 
 Then Select Start Full Synchronization clicks ok on new window.



You can see Profile synchronization Status changed into “Synchronizing”
 It’ll take somewhere 10 -15 min to Sync up with AD. After 5 min when you refresh this window you’ll see Number of User Profile Changing (Increasing ).


Once it done go to the Manage User Profile and try to search a user you will get details on that particular person.



This is how we can Sync User Profile Service with Active Directory. 

Next question you might ask from me "How to Deal with User Profile Service in code Level" - no worries guys I'll explain that in my next posts.  


ok That's It ... 
HAPPY CODING