Tuesday, November 5, 2013

SharePoint Client Object Model ( SP - COM )
Part - 2

[ Let's Code - Basic Coding Techniques in COM ].

I'll start with basic coding blocks and techniques which we use in ECMA scripts. but when you are in a practical environment you will need to know more coding styles and the best practicess which I'm gonna talk in Part 3 and onward.

›Some basics

First this Coding or Scripts lines are so similar to Server coding in SP 2010 so it's not hard to keep them in mind. 
How to access a list and get Data from a list in Server code here is the sample: 

using (SPSite site = new SPSite(topSiteUrl)) Create SharePoint Site Object
{
  using (SPWeb Web = site.OpenWeb())Create SharePoint Web Object based on site
  {
   string listUrl = Utilities.ConcatPath(topSiteUrl, "Lists/XXXinformation"); 
   var XXXList = Web.GetList(listUrl);Access list by URL (can be done using title)
   SPQuery sp_Qry = new SPQuery();Create CAML Query object
   sp_Qry.RowLimit = 20;
   SPListItemCollection itemCol = XXXList.GetItems(sp_Qry); Extract Data from the list
                  
foreach (SPItem item in itemCol) 
     {- Loop through the Item collection and get item data.
item["Title"].ToString()
new SPFieldUrlValue(item["XXXSiteURL"].ToString()).Url
   }
}
}

ECMA Scripts are almost same. 

First you need to load sp.js file which is the ECMAScript class library [Find the namespaces that are available from the SP.js] to do that you need to use following Function. [ Here youFunction is the function which include other coding.]

ExecuteOrDelayUntilScriptLoaded( youFunction , "sp.js");
in SharePoint 2013 you need to call this as,
SP.SOD.executeFunc('sp.js', 'SP.ClientContext', youFunction );

with-in the youFunction  you can implement following scripts,

first of all you need to create a Context object which Similar to "Microsoft.SharePoint.SPContext

var context = new SP.ClientContext(Url); -Default Way
  var context = new SP.ClientContext(); - get root context
  var context = new SP.ClientContext.get_current(); - get Current context

through Context you can get web object which similar to SpWeb

var web = context.get_web(); - Get Current Web (when you are in subsite it take tha subsite web object)
§[var web = context.get_site().get_rootWeb();] - Get Root Web (even when you are in subsite it takes root web)

Then you need to create a List object as SPList
var List = web.get_lists().getByTitle(‘Title of List Item'); - Note: you can access list only by it's title [i couldn't find any ]

Create a Caml query object aSPQuery as follows,
var camlQuery = new SP.CamlQuery();
camlQuery.set_viewXml(QueryLatest);
Note: this 'QueryLatest' is what you write you CMAL Query.
var QueryLatest =
'<View>' +
       '<Query>' +
              '<Where>' +
                     '<Eq><FieldRef Name=\'Disabled\' /><Value Type=\'Boolean\'>0</Value></Eq>' +
              '</Where>' +
              '<OrderBy><FieldRef Name=\'FooterOrder\' /></OrderBy>' +
       '</Query>' +
'</View>';

then defile a Class variable as var collListItem; then,


this.collListItem = List.getItems(camlQuery);

This is how you wrap the ECMA object which filled with required details and bind with context then send it back to the WCF service (client.svc)

context.load(collListItem);

context.executeQueryAsync(Function.createDelegate(this, this.onListDataLoadQuerySucceeded), Function.createDelegate(this,
this.onListDataLoadQueryFailed));

you need to have two functions as you code with Ajax objects one is for Success and one is for fail. and it's asynchronous call, as it involve with web service.
 functions should be like this,
 
function onListDataLoadQuerySucceeded(sender, args) {
      
}

function onListDataLoadQueryFailed(sender, args) {

}

If Service deliver the results successfully onListDataLoadQuerySucceeded will fire. and you can get Item count by using, this.collListItem.get_count() and if you need to iterate through results you need to have a Enumerator object, var listItemEnumerator = collListItem.getEnumerator(); then you can iterate as like this,
          
while (listItemEnumerator.moveNext()) {
      
              }
get current item in the loop as, var listItem = listItemEnumerator.get_current();Then access List Item columns as, listItem.get_item("Title").

All-together :  

var ListName = 'Footer';
var Query =
'<View>' +
       '<Query>' +
              '<Where>' +
                     '<Eq><FieldRef Name=\'Disabled\' /><Value Type=\'Boolean\'>0</Value></Eq>' +
              '</Where>' +
              '<OrderBy><FieldRef Name=\'FooterOrder\' /></OrderBy>' +
       '</Query>' +
'</View>';

$(function () {
       ExecuteOrDelayUntilScriptLoaded(GetFooter, "sp.js");
});
var ShowcorFooter = "";
var collListItem;
function GetFooter() {
    var context = new SP.ClientContext();
    var web = context.get_site().get_rootWeb();
       var List = web.get_lists().getByTitle(ListName);

       var camlQuery = new SP.CamlQuery();
       camlQuery.set_viewXml(Query);
       this.collListItem = List.getItems(fcamlQuery);
       context.load(fcollListItem);
       context.executeQueryAsync(
                     Function.createDelegate(this, this.onFooterListDataLoadQuerySucceeded),
                     Function.createDelegate(this, this.onFooterListDataLoadQueryFailed));
}

function onFooterListDataLoadQuerySucceeded(sender, args) {
       var flistItemEnumerator = fcollListItem.getEnumerator();
              if (this.fcollListItem.get_count() > 0) {
             
              while (flistItemEnumerator.moveNext()) {
                    
                     var footerListItem = flistItemEnumerator.get_current();
                     var link = footerListItem.get_item("Link").get_url());
var title =  footerListItem.get_item("Title"));
                    
              }
       }
}

function onFooterListDataLoadQueryFailed(sender, args) {
alert("Something Wrong");
}

In Next Post I'll discuss good techniques and best practices through a web Picture rotate custom web part.

ok That's It ... 
HAPPY CODING

Monday, November 4, 2013

SharePoint Client Object Model ( SP - COM )

Part - 1

[ Introduction : Theoretical background and Overview]  

One Project which I involved as a developer from the scratch is Called ShawCor, this system ( intranet ) was developed for ShawCor Ltd. ( ShawCor Ltd. is a growth-oriented, global energy services company). so we decided to develop this based on COM (Client Object Model), so Why we decided ? and What is this COM ? will be Discussed. 

What is Client Object Model in SharePoint ? 

The definition of Client Object Model is kind of a boring but you can extract some of the words and get an idea so here we go please have a look at the words which highlighted 
"The Client Object Model (OM) is a new programming interface for SharePoint 2010 where code runs on a user’s client machine against a local object model and interacts with data on the SharePoint Server. Client OM methods can be called from JavaScript, .NET code or Silverlight code and makes building rich client applications for SharePoint easy."

So in Simple words this is a new programming interface which come with SP 2010 and using JS, silverlight kind of a Scripts which runs on a Client machine but still it interact with SP server to extract data.

Why we needed it ? [What do we want to achieve?]

 As in the ShawCor Project, Sometimes we want to extend SharePoint by adding functionality which will execute on the client-side. imagine is it requires no post-backs (specially in New popups Animations), in other words, we want some mechanism to execute code on the client-side but then still interact with SharePoint data and functionality which reside on the server.

  • Building Silverlight components, 
  • Build web parts which contains client side code like ajax or silverlight, 
  • Extend an existing Windows forms application which contains client-side code.
  What about SharePoint 2007 ? 

In SP 2007 you had to use the native SharePoint Web Services or build new custom web services which will be hosted on the SharePoint server. Remember that custom web services will use the server object model. Deploying custom web services onto the server creates an administrative overhead and introduces a risk. so I can not recommend 

This is How SP 2007 works in similar process.


So it is very obvious that we needed some mechanism to build client-side code which has an awareness and access to the SharePoint Server Object Model.
This is what Required.

Microsoft helped solve this problem for us by introducing the SharePoint 2010 Client Side Object Model. Now we have a mechanism to extend SharePoint functionality through client-side code..without using SharePoint Web Services !!!

›Mechanism(s) behind it.

Here I have put a simple fig: to understand how this works. 
1) First When your written ECMA (will explain later ) Script convert into a ECMA Script Object model like Ajax Object do
2)It go through a Proxy do security validations.
3)And reach a client.svc, it's a WCF service which analyze this Clint object and understand the requirement then Convert into the Sever Codes which SP server can understand.
4) send the Server code into the SP server 
5/6) then sever will communicate with the content Data base and do what it asked, things like get data or write records. 
7)Then send the response to the web service 
8)Web service again analyze the Server Code and Filled the return data into a ECMA Object and send it to the Browser to do that it required. 

Advantages of Client Object model.

  • We can access SharePoint data from the client side browser itself with Silverlight and ECMAScript applications. 
  • Web parts with very rich user interface can be developed with the help of Silverlight and jQuery 
  • COM along with JavaScript or jQuery can be implemented with just a Content Editor Web part within the browser or from SharePoint designer without opening Visual Studio. 
  • When you save your site as a template. The application developed with an ECMAScript or Silverlight application implemented with Client Object Model would come along with the template. 
  • No IISREST is required. 
  • No SharePoint installation is required in the development machine.

Disadvantages of Client Object Model.


  • We cannot elevate the privilege or Impersonate in COM as in the Server Object Model. That is, we cannot use the RunWithElevatedPrivilege kind of a delegate. Therefore, the result retrieved using COM will always be security trimmed by default. 
  • The range of classes available to access SharePoint data is very limited in COM. For example, we do not have Classes for accessing User Profiles. 
  • We cannot access the objects of another site collection in COM while implementing in Silverlight or in an ECMAScript. We will get “The security validation for this page is invalid.”
So those are the theoretical thing you need to know on using COM, in the Next part [Let's Code] you get to know how to code it. 

ok That's It ... 
HAPPY CODING

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