Friday, April 22, 2016

SharePoint Best Practices Coding


SharePoint Best Practices Coding

Description: mail-image

If you are developer of any specific technology, you should know about best practices of that technology. You may ask why best practices important? Best practices are based on real time experience. so if you are unaware about it, you will end up writing unmaintainable, buggy or unoptimized code.

Lets start discussion about SharePoint best practices with real time example.


  1. Don't cache SharePoint objects that are not Thread Safe
Let's take real time scenario, we have to bind dropdown list with the SharePoint list. We know SharePoint list which we are binding with dropdown list is not going to change frequently, so caching will be better option to improve the performance of theapplication. Sample code is mentioned below:
                      SPListItemCollection colItems;
            if(null != HttpRuntime.Cache[key])
            {
                ddlItems = (SPListItemCollection)HttpRuntime.Cache[key];
            }
            else
            {
                // Do query on sharepoint listand cach SPListItemCollection object
            }
But we are unaware that SPListItemCollection object contains an embedded SPWeb object that is not thread safe and should not be cached.

Good Coding Practice is to cache DataTable in place of SPListItemCollection object.
Sample Code:
         private static object _lock =  new object();
          private DataTable GetDropDownItems()
         {
         DataTable dtDropDownItems;
   SPListItemCollection objListItems;
   lock(_lock)
   {
             dtDropDownItems= (DataTable)Cache["CachedDropDownItems"];
           if(dtDropDownItems== null)
           {
              objListItems = //Do query onSharePoint List
              dtDropDownItems= objListItems.GetDataTable();
              Cache.Add("CachedDropDownItems ", dtDropDownItems,..); // provide rest of the parameter of this method
           }
   }
   }

Note: There are various methods to cache object like HttpRuntime, System.Web.Caching.Cache,  and HttpContext.Current.Cache. Choose one to the method to cache depending upon your application requirement.

    2.
 Retrieve or fetch SPList instance from SPWeb object: There might be the multiple approach to get the instance of SPList in SharePoint. But while developing an application we should keep in mind about performance of the application. Mentioned below are two approach to achieve the same. 

        Approach 1:
 Not Recommended
       
 SPList objSpList = <SPWeb>.Lists["<List Title>"];   

        Approach 2:
 Recommended
       
 SPList objSpList = <SPWeb>.GetList("<List URL>");
    
        In the first approach, SharePoint loads "metadata" of all the SharePoint lists of current
 SPWeb object and then create SPList instance by Title comparison and also if Title of SharePoint list gets changed, There will be a code change. But in the second approach, SharePoint fetches GUID of the SharePoint list by list url and then loads the "metadata" of that particular list. User can not update the list URL after SharePoint list creation. So there is no possibility of any code change in this approach. 

    3.
 JavaScript methods call on page load in SharePoint: Sometime we need to call JavaScript methods on page to change UI or to set some controls value. we can use window.onload event to achieve this functionality. But I personally recommend that to use "_spBodyOnLoadFunctionNames" method provided by SharePoint because sometimes window.onload don't work properly.
        Approach 1:
 Not Recommended
        window.onload = funcation(){//JavaScript code};
        window.onload =
 <JavaScript method name>;

        Approach 2:
 Recommended
        
_spBodyOnLoadFunctionNames.push('<JavaScript method name>');

     4. Set RowLimit, ViewFields, and ViewFiledsOnly properties while fetching data from SharePoint list:
        Let take me take an example to make understand importance of these properties.

      Scenario: Suppose there isa list to store employee details. Following fields are present in this list:
·    Name
·    Designation
·    Domain
·    Address
·    Email
·    Contact Number
·    Rating
      We have to create a webpart to show top 5 employees name, designation and email in the home page of site based on employee rating.

        To achieve above mention scenario, we will end up with mentioned below code sample:

         Bad coding:
using (SPSite objSite = new SPSite("<Site URL>"))
{
    using (SPWeb objWeb = objSite.OpenWeb())
    {
        SPList objList = objWeb.GetList("<List URL>");
        SPQuery objQuery = new SPQuery();
        objQuery.Query = @"<OrderBy>
                                <FieldRef Name='ID' Ascending='False' />
                            </OrderBy>";
        SPListItemCollection employeeCollection = objList.GetItems(objQuery);
    }
}

In the above mentioned codeblock, we will fetch all the fields data but we have to display only 3 fieldsdata in the webpart. So there will be performance hit. As a good practice weshould pass ViewFields also. so that our query will return required fields data only.

            Add following line of code to improve the performation:
         Good coding
//We have specified view fields, now our query will fetch value of these three fields data.
objQuery.ViewFields = @"<FieldRef Name='Name'/>
                        <FieldRef Name='Designation'/>
                        <FieldRef Name='Email'/>";

Even though we have specified view fields, still SharePoint fetches following fields data:

·     ID
·    Created
·   Modified
As per problem statement, we do not want these fields data. SPQuery object has property called ViewFieldsOnly. If we set this property to true, these fields data will not come with the query result. It means, to improve our query performance, we will have to add one more line in our code:

Good coding:


   objQuery.ViewFieldsOnly = true;                                                                                      
   
Note: If you have to do write operation on fetched records by our query, do not set ViewFieldsOnly property to true otherwise while updating any item you will get following exception: "Value does not fall within the expected range."

Still we can improve our code. Here we need to show only 5 employees details and our query will fetch all employee details. So we can improve our code by providing RowLimit to 5.

Good coding:

  objQuery.RowLimit = 5;                                                                                                    
 
 

Note:
  Most of the time we do not know how many records will fetch after query execution. But as best practice we should set RowLimit if we know the threshold of our query.

Now we know, when to set which property and why these properties are important.



https://sureshunakka87.wordpress.com/2014/05/03/best-practices-using-disposable-windows-sharepoint-services-objects/

 

Best Practices: Using Disposable Windows SharePoint Services Objects

Posted on by nakkasuresh
 SPWeb.Lists Vs SPWeb.GetList
 There are many posts on this topic. So why I am writing one more post? Well just to share my experience and hope others will benefit from this.
SPWeb.GetList (string strUrl) – Good
using (SPSite site = new SPSite(strSite))
{
using (SPWeb web = site.OpenWeb())
{
SPList oList = web.GetList(http://Site/list/AllItem.aspx)
}
}
In this case, first retrieves the list GUID from the url (database hit), then it loads the metadata* for that specific list.
SPWeb.Lists (“name”) – Not Good 
using (SPSite site = new SPSite(strSite))
{
using (SPWeb web = site.OpenWeb())
{
SPList oList = web.Lists [“MyList”]
}
}
Please reffer the url for more Disposing sharepoint objects .
Cheers!!!!


Sunday, December 20, 2015

Validating the People Picker in SharePoint with J query

Validating the People Picker in SharePoint with J query

--------------------------------------------------------------------------------------

// Peoplepicker name: pplName




 function CheckPeoplePickerIsEmpty()
{
            var value = $(".pplName span.ms-entity-resolved").attr("title");  
          
          if (value == undefined) {
                $('#pplmsg').text("Please select people name.");    // Take span for printing the msg
            }
            else {
                $('#pplmsg').text("");
            }
}


=======================================================================

When button not click by Jquery OnClick function, try to add $(document).ready. see below

When button not click by Jquery OnClick function, try to

add  $(document).ready. see below

------------------------------------------------------------------------------------------------------------
 $(document).ready('#button').click(function(event){              
   //  Ensure that the SP.UserProfiles.js file is loaded before the custom code runs.
   // SP.SOD.executeOrDelayUntilScriptLoaded(getCurrentUser, 'SP.UserProfiles.js');
     getCurrentUser();

  });
----------------------------------------------------------------------------------------------------------

Querying List Items from Large Number of Sites in SharePoint

Querying List Items from Large Number of Sites in SharePoint


Source Link: http://www.vrdmn.com/2012/11/querying-list-items-from-large-number.html

When scouting the web for working with SharePoint Large Lists, you can find many articles which deal with fetching a huge number of items from one particular list. But very little data when you want to fetch items from a large number of sub sites. So after a little bit of poking around, I decided to blog about some of my findings here:

The Scenario:

Here are the conditions on which I was testing:
  • 1 Site Collection
  •  500 Sub sites
  •  1 Task List in Each sub site - &gt; 500 Lists
  •  10 items in each List -&gt; 5000 List Items

 So the total count of items I had to query was about 5000 and according to the test conditions, the items which would match the query were not more than 1200 at a time.

The Tools:

The tools I was using for measuring the performance were nothing extraordinary:

1)  I was using the StopWatch Class from the System.Diagnostics namespace. This class provides a fairly simple and easy mechanism for recording the time a particular operation took to execute.
This MSDN link has excellent examples on how to use the StopWatch class for performance measuring

2) The Developer Dashboard has always been my goto tool for performance measuring. I don’t know how I used to get by before I started using it. It provides a wealth of information about the page load. It can provide you with the time taken, the database calls made, the stack trace and a whole lot of other very useful information. A good tutorial on the Developer Dashboard can be found here.

SPSiteDataQuery:

The SPSiteDataQuery class is the heart of architecture when you want to get data from multiple sites. This class by itself does not use any form of caching and always returns data based on the real time queries. So even if it takes a bit longer to fetch the data, it is guaranteed that you will get all the current results and your users will never have to wait to see their new items to be returned by the query.

Here is the code for doing a simple query with the SPSiteDataQuery class:

SPSiteDataQuery query = new SPSiteDataQuery();
query.ViewFields = "\"Title\" /&gt;\"
DueDate\" /&gt;";
query.Query = @"



" +
SPContext.Current.Web.CurrentUser.Name
+ @"



Completed



";
//Query only the Tasks List in each web.
query.Lists = "\"107\" MaxListLimit=\"0\"/&gt;"
;
/*Specifying the MaxListsLimit as 0 means that there is no limit on how many lists
in the site collection will be queries. If you want you can limit this number to
increase your performance.*/
query.Webs = "\"Recursive\" /&gt;"
;
//Specifying the row limit will limit the number of items which will be returned.
//query.RowLimit = 100;
DataTable results = SPContext.Current.Web.GetSiteData(query);

view rawspsite.cs hosted with ❤ by GitHub

Here is a stack trace of the internal methods which are called by the SharePoint framework when a SPSiteDataQuery is used:


So as you can see, it calls the SPRequest.CrossListQuery method which internally makes queries to the Database to fetch the relevant results.

When querying the database the procedure proc_EnumListsWithMetadata is used. You can have a look at this procedure in your Content DB. It queries several tables such as the dbo.AllListsdbo.AllWebs etc. to fetch the relevant results.

Time taken to query 5000 items in 500 sub sites and return 1200 matching items:

 650ms average on each load.

CrossListQueryInfo:

The CrossListQueryInfo class is another mechanism you can use to fetch the List Items from multiple sites. This class internally uses the SPSiteDataQueryclass to actually fetch the items from the database and when the items are returned, it stores them in the object cache of the Publishing Infrastructure. When any more calls to the same data are made subsequently, then the data is returned from the cache itself without making any more trips to the database.

The working of the CrossListQueryInfo class largely depends on the object cache of the Publishing Features of SharePoint server. So you cannot use this class in SharePoint 2010 Foundation or in sandbox solutions. Also, the default expiry time of the object cache is set to 60 seconds. So you might want to change that time depending upon your environment requirements.

Here is the same code for using the CrossListQueryInfo class:

CrossListQueryInfo query = new CrossListQueryInfo();
query.ViewFields = "\"Title\" /&gt;\"
DueDate\" /&gt;";
query.Query = @"



" +
SPContext.Current.Web.CurrentUser.Name
+ @"



Completed



";
query.Lists = "\"107\" MaxListLimit=\"0\"/&gt;"
//Tasks Lists
query.Webs = "\"Recursive\" /&gt;"
;
//query.RowLimit = 100;
//Make sure to set this property as true.
query.UseCache = true;
CrossListQueryCache cache = new CrossListQueryCache(query);
//Make sure to use one of the overloads of the GetSiteData method which takes in the SPSite parameter
//and not the SPWeb parametre.
DataTable results = cache.GetSiteData(SPContext.Current.Site);

view rawcross.cs hosted with ❤ by GitHub

Make sure to set the CrossListQueryInfo.UseCache as true if you want to use the caching features. Another very important thing to mention is that there are 4 overloads of the CrossListQueryCache.GetSiteData method and only 2 of them support caching.
So only use the methods which accepts the SPSite object as one of the parameters if you want to use caching in your code.
The Stack Trace of the CrossListQueryInfo class looks like this:


So as you can see, the Publishing.CachedArea is queried first to check whether the items exist in the cache. If they don’t exist, then a call to theSPSiteDataQuery is made which fetches the values from the database and stores it in the cache. All the next subsequent calls will find that the items are present in the cache so no more calls with the SPSiteDataQuery class will be made.

As a result, the very first call will take longer than a vanilla SPSiteDataQuery call as under the hood, the CrossListQueryInfo is not only fetching the items but also building a cache with them.

Time taken to query 5000 items in 500 sub sites and return 1200 matching items:
 2000ms on first load and 30ms average on each subsequent load until the object cache expires.

PortalSiteMapProvider:

The PortalSiteMapProvider is a class which can used to generate the navigation on SharePoint Publishing sites. The Global navigation, the Quick Launch and the Breadcrumb navigation can all be generated with help of the PortalSiteMapProvider. It also provides methods to query sub sites, lists and list items with help of caching.

The main advantage of the PSMP is that it queries the SharePoint change log to check whether any changes have happened to the data being queried. If yes, then only the incremental changes are fetched and thus the cache is updated accordingly.

However, my tests showed that the PortalSiteMapProvider.GetCachedSiteDataQuery method which is used to get items from multiple sub sites does not maintain an incremental cache and it only fetches the new or updated items when the object cache has expired.

So essentially when querying for items from multiple sites, the CrossListQueryInfo and the PortalSiteMapProvider behave almost similarly.

Here is the sample code for the PortalSiteMapProvider:

SPSiteDataQuery query = new SPSiteDataQuery();
query.ViewFields = "\"Title\" /&gt;\"
DueDate\" /&gt;";
query.Query = @"



" +
SPContext.Current.Web.CurrentUser.Name
+ @"



Completed



";
query.Lists = "\"107\" MaxListLimit=\"0\"/&gt;"
//Tasks Lists
query.Webs = "\"Recursive\" /&gt;"
;
//query.RowLimit = 100;
PortalSiteMapProvider ps = PortalSiteMapProvider.CurrentNavSiteMapProviderNoEncode;
PortalWebSiteMapNode pNode = ps.FindSiteMapNode(curWeb.ServerRelativeUrl) as PortalWebSiteMapNode;
DataTable results = ps.GetCachedSiteDataQuery(pNode, query, SPContext.Current.Web);

view rawportal.cs hosted with ❤ by GitHub

The stack trace for the PortalSiteMapProvider:


You can see that it’s very similar to the CrossListQueryInfo.

Time taken to query 5000 items and return 1200 matching items:
 2000ms on first load and 30ms average on each subsequent load until the object cache expires



So these are some of the methods you can use to query multiple List Items in multiple sites. Hope you had a good time reading through the post. 

Happy SharePointing!