Wednesday, February 1, 2017

Best Practices: SharePoint Object Model for Performance Tuning

While working with SharePoint object model, most of developers will use SPWeb, SPSite, SPList objects intensively.
I had worked with some customers who reported performance issues in their production environment after their project deployment. Their code works well in most of the scenarios but whenever the data get increases then there might be potential performance hits because of not handling the APIs properly.
In this post I will give information about some common methods that we are using in most of the scenarios and very important points that we need to remember in perspective of application’s performance. We do have two cool MSDN articles gives information about the best practices with SharePoint object model and I will recommend you all to go through those articles as well. Also we do have an excellent blog by Roget Lamb by giving the detailed information of Dispose Patterns with examples.


Best Practices: Common Coding Issues When Using the SharePoint Object Model


Best Practices: Using Disposable Windows SharePoint Services Objects


Roger Lamb’s cool post about SharePoint 2007 and WSS 3.0 Dispose Patterns by Example


Lots of situations where we will use APIs for retrieving information about Lists and List Items. In SharePoint, lists are the objects storing large amount of data. So we need to be little cautious while working with those APIs, because internally those APIs are calling some SQL queries to pull the data which has been stored the SharePoint Content DBs.
The performance issues may happen in some cases if numbers of lists are very high or in some cases total number of lists will be less but the items will be very large.  
First we can take a look at different approaches of getting SPList instance and we can choose the best method to increase the performance.  We have more than one method or property which will return the same result. For Eg: SPList.Item.Count & SPList.ItemCount will return the number of items, so here we need to decide which one need to opt in our code implementation to enhance the performance.
Scenario 1 : Retrieve SPList instance
SPWeb.Lists (“name”) – Not Good L

          using (SPSite site = new SPSite(strSite))

            {

                using (SPWeb web = site.OpenWeb())

                {

                    SPList oList = web.Lists [“MyList“]

                }

             }
In this case, it loads the metadata* of the all lists in that specific SPWeb object. Then it does SPList.Title comparison with metadata of all the lists returned and then it returns the matching list from the SPWeb.Lists collection.


SPWeb.GetList (string strUrl) – Good J

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.
metadata * = list of all information of List like its schema, fields info, content type info, column and items count.
Consider a scenario of a SharePoint site which contains 1000 lists.


If we use SPWeb.GetList(), it will load the SPList by finding out the exact GUID of that SPList from the SharePoint content DB and loads the metadata.
But if that is the scenario with SPWeb.Lists[“MyList”] then, SPWeb.Lists will load the metadata of  all the 1000 lists in memory and then it does SPList.Title  ( here it is “MyList”) comparison with metadata of all the lists returned and then it returns the matching list from the SPWeb.Lists collection.
If you debug the code in winDbg then you can find out the GC Heap size and then you can realize how badly it is affecting the performance of your application, sometimes for each SPList it will take some MB’s.
So now we can consider this matter while writing code and use SPWeb.GetList() instead of using SPWeb.Lists[“MyList”].
Scenario 2 : Retrieve SPListItem
SPList.Items[int idx] – Not Good L

          using (SPSite site = new SPSite(strSite))

            {

                using (SPWeb web = site.OpenWeb())

                {

                  SPList oList = web.GetList(“http://Site/list/AllItem.aspx”);

                    for(int idx =0; idx< oList.ItemCount; idx ++)

                    {

                        string strLstItemName = oList.Items[idx].Name;

                    }

                }

            }
In this case, for each iteration oList.Item[idx] will load a SPListItemCollection. Eg: consider a list has 1000 list items. So whenever this code executes, for each iteration it will create a separate SPListItemCollection and it will create a huge memory consumption in the GC Heap by creating 1000 SPListItemCollection instances


SPListItemCollection[int idx] –  Good J

  using (SPSite site = new SPSite(strSite))

            {

                using (SPWeb web = site.OpenWeb())

                {

                   SPList oList = web.GetList(“http://Site/list/AllItem.aspx”);

                    SPListItemCollection oListItems = oList.Items;

                    for(int idx =0; idx< oList.ItemCount; idx ++)

                    {

                        string strLstItemName = oListItems[idx].Name;

                    }

                }

            }              
In this case, we can see the the only code change between this one and the not good one is, here we are first taking all the items from the list and populating it in a SPListItemCollection. And then we are iterating only that SPListeItemCollection and finding out the specific list item. Here the advantage is that, in the memory this code will load only one SPListItemCollection.

Scenario 3 : Retrieve SPListItem in Event Handlers
SPListItem – Not Good L

public override void ItemAdded(SPItemEventProperties properties)

 {

  using (SPSite oSite = new SPSite(properties.WebUrl))

   {

    using (SPWeb oWeb = oSite.OpenWeb())

    {

     SPList oList = oWeb.Lists[properties.ListId];

     SPListItem oListItem = oList.GetItemByUniqueId(properties.ListItemId);

    }

   }

 }
In this case, we are unnecessarily giving extra load to the memory by adding so many memory consuming APIs.   For each iteration, oList.Item[idx] will load a SPListItemCollection. Please see the Good method below.



SPListItem – Good J

public override void ItemAdded(SPItemEventProperties properties)

 {

  SPListItem oItem = properties.ListItem;

 }
In this case, we have reduced lots of code and it will return the current ListItem by using this single line of code. Avoid creation of SPWeb & SPSite instances, because in an event handler those are directly accessble through the SPItemEventProperties.

Scenario 4 : Retrieve SPListItem Count

SPList.Item.Count – Not Good L

using (SPSite site = new SPSite(strSite))

      {

       using (SPWeb web = site.OpenWeb())

        {

          SPList oList = web.GetList(“http://Site/list/AllItem.aspx”);

          int iCount = oList.Items.Count;

        }

      }
In this case, oList.Items.Count, first it will load all the SPListItems in the memory and then it will find out the total count. For eg: Consider a list with 1000 list items. Then in this scenario the above code will load all the 1000 SPListItems and then return the total count, which will really create some performance hit.

SPList.Item.ItemCount – Good J

using (SPSite site = new SPSite(strSite))

      {

       using (SPWeb web = site.OpenWeb())

        {

          SPList oList = web.GetList(“http://Site/list/AllItem.aspx”);

          int iCount = oList.ItemsCount;

        }

      }
In this case, ItemCount is a part of metadata of the SPList object and this will get generated whenver we create a SPList instance. So there is no any overburden to the list to find out its total number of list items.


Scenario 5 : A list of recommended  properties and methods

Not Good (replace this by the Good one)
Good  J

 

SPList.Items.Count

 

SPList.ItemsCount

 

SPList.Items[Guid]

 

SPList.GetItemByUniqueId(Guid)

 

SPList.Items[Int32]

 

SPList.GetItemById(Int32)

 

SPList.Items.GetItemById(Int32)

 

SPList.GetItemById(Int32)


Scenario 5 : Specify the RowLimit Property while using SPQuery Object

SPQuery.RowLimit  Good J
SPQuery oQuery = new SPQuery();

oQuery.RowLimit = 2000;
 
Performing an SPQuery without setting RowLimit will perform purely and will be fail on large lists. Thus it will be always recommend to specify the RowLimit between 1 and 2000. Because if we didn’t mention it, in SQL server it ill return the resullt by using “select top x from table”, here the x will be a very large number. So it would give a very good performance if we limit the row by explicilty setting the RowLimit.
Also, the query must use an indexed field or it will cause a complete table scan and WSS will block it on a large list.


I hope all these information will help the developers while writing the code in their custom SharePoint applications. Since in SharePoint most of the data are storing in the lists, the maintenance of those tables in DB as well through code (by querying through SharePoint APIs) will be always be a best practice. Also everybody can consider these points while reviewing the code.

Wednesday, April 13, 2016

Pre-Expand the “Show More” link in a SharePoint Task List





Just add a Content Editor web part on the page(New,Edit and Display form) and fill it with the following script:

<script type="text/javascript">
    (function () {
        _spBodyOnLoadFunctionNames.push("rlfiShowMore");
    })();
</script>

Wednesday, February 4, 2015

How to Fix Error “HTTP 500 Internal Server Error in SharePoint 2013”

Once in a whereas I encounter a slip-up that doesn't give any useful data. this can be specifically what happened the opposite day I opened my SharePoint website and found out that the web site cannot show the page due to HTTP 500 Internal Server Error on my SharePoint 2013. First thing I attempted to try and do is open SharePoint Central Administration, to see if i get constant error message. Strangely, I used to be ready to open Central Administration with none errors.



Open the IIS Manager to make sure SharePoint 2013: eighty Application Pool was running, and that i noticed  that SecurityTokenServiceApplicationPool application pool was stopped.



I started SecurityTokenServiceApplicationPool application pool, refreshed my SharePoint website however that didn’t resolve the problem. I opened IIS manager and noticed  that SecurityTokenServiceApplicationPool was stopped once more.





In that case, smartest thing to try and do was to open IIS events log and check what’s occurring with SecurityTokenServiceApplicationPool application pool.
IIS event log showed the warning ID 5021:
The identity of application pool SecurityTokenServiceApplicationPool is invalid. The user name or password that is specified for the identity may be incorrect, or the user may not have batch logon rights. If the identity is not corrected, the application pool will be disabled when the application pool receives its first request.  If batch logon rights are causing the problem, the identity in the IIS configuration store must be changed after rights have been granted before Windows Process Activation Service (WAS) can retry the logon. If the identity remains invalid after the first request for the application pool is processed, the application pool will be disabled. The data field contains the error number.
To Fix this error:

1. Back to IIS manager -> SecurityTokenServiceApplicationPool application pool-> Advanced Settings.




2. Go to the Identity option.
3. Then, Update the user’s credentials and click OK button. I perform IISreset.
4. Open the IIS manager once more to examine if it worked. SecurityTokenServiceApplicationPool was now started and didn't stop any longer.




5. Finally, my SharePoint 2013 site was operating again :)


Fixed:--SharePoint Designer 2013 Crashing on Open Site

The Problem

When I installed SPD2013 on my laptop, all went well. However, every time I tried to use the Open Site dialog, it would crash. SharePoint Designer 2010 (SPD2010) was still working fine when I accessed other 2010-based installations, but not SPD2013.
I found a fix that worked for me in the Technet forums. You may or may not want to trawl through the thread, as it is quite long. Instead, here’s the Cliff Notes version of what worked for me.

You can repair your SPD 2010 to restore the regkey for SPD2010.
The issue might happen in case the ClientGUID of the Open Site dialog in SPD14 is the same as the one of the open site dialog in SPD 15 in a certain Side by Side environment.
(this repro’s only in a specific environment, but I couldn’t find the enviroment yet and when the GUIDs could be the same)
so I have couple of questions. Sorry to bother you, :(
1. Could you please check if ClientGUID value under HKEY_CURRENT_USER\Software\Microsoft\Office\14.0\Common\Open Find\Microsoft SharePoint Designer\Settings\Open Site is the same as the ClientGUID value under HKEY_CURRENT_USER\Software\Microsoft\Office\15.0\Common\Open Find\Microsoft SharePoint Designer\Settings\Open Site?
2. If the values are the same, could you please check if the crash still happens after removing both registry keys?
3. Have you ever installed any other version of SPD15 on your machine? (e.g. beta version) or any other version of SPD14?
4. if the issue still happens at #2, how about removing the registry key HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\ComDLg32\LastVisitedPidlMRU ?
Points 1 and 2 did the trick for me. Apparently both SPD2010 and SPD2013 had the same GUID for the ClientGUID value in the registry. I had not installed any betas of SPD2013 on my laptop because I was concerned about exactly this sort of incompatibility. (I’d limited my use of SPD2013 to launching it inside virtual machines.)

The Fix

If you have this problem and want to fix it, here are the steps.
Open the Registry Editor. You can do this by going to the Start menu (I’m still a Windows 7 stalwart, so I can’t vouch for how this might work on Windows 8), choosing “Run”, and typing “regedit” in the Open: box.
Look for the keys:
HKEY_CURRENT_USER\Software\Microsoft\Office\14.0\Common\Open Find\Microsoft SharePoint Designer\Settings\Open Site
and
HKEY_CURRENT_USER\Software\Microsoft\Office\15.0\Common\Open Find\Microsoft SharePoint Designer\Settings\Open Site
In my case, they were identical, as shown below.
SharePoint Designer 2010 (14.0)
image

SharePoint Designer 2013 (15.0)
image
Delete both of the ClientGUID keys. You can do this by highlighting the key and hitting the Delete key or right clicking and choosing Delete.
Once I had deleted these two registry keys, I was able to open sites in both versions of SharePoint Designer with no problems.
Unfortunately, the two versions of SharePoint Designer seem to use the same recent sites list, so I see the same Recent Sites in both versions. This is going to make it confusing when I am trying to figure out which site to open. Now I’m a three SharePoint Designer version guy, as I’m still using SPD2007 and SPD2010 for client work in addition to SPD2013. Yeesh.

How to Resolve Error Creating Publishing Sites In SharePoint ?

I have come upon a problem in SharePoint 2013 related to the creation of publishing Sites. rather than the site being created, the user is confronted with the error below.



A list of errors logged in the ULS is at the top of this post, however the problem is because of access being denied to __DeviceChannelMappings.aspx.

To resolve the error use SharePoint Designer to assign the Restricted read access to _catalogs/masterpage and DeviceChannels.
Within SharePoint Designer, right-click on masterpage and select properties.

2

Now, Click on Permissions for this list
3

Then Assign Restricted Read permissions to the appropriate user, or group.
4
Next, repeat the process for the DeviceChannels folder.

5

List of ULS error messages:
<nativehr>0x81070211</nativehr><nativestack></nativestack>Cannot open file “_catalogs/masterpage/__DeviceChannelMappings.aspx”.
System.UnauthorizedAccessException: Access is denied. (Exception from HRESULT: 0x80070005 (E_ACCESSDENIED)),
Unexpected error when trying to populate mobile mappings file ‘_catalogs/masterpage/__DeviceChannelMappings.aspx’ in web ‘/SITENAME': Access is denied. (Exception from HRESULT: 0x80070005 (E_ACCESSDENIED))
A runtime exception was detected. Details follow.  Message: Access is denied. (Exception from HRESULT: 0x80070005 (E_ACCESSDENIED))  Technical Details: System.UnauthorizedAccessException: Access is denied. (Exception from HRESULT: 0x80070005 (E_ACCESSDENIED))    
Watson Reporting Cancelled) System.UnauthorizedAccessException: Access is denied. (Exception from HRESULT: 0x80070005 (E_ACCESSDENIED))   
Event log message was: ‘Failed to initialize some site properties for Web
at Url: ‘http://SITENAME&#8221;. Exception was: ‘System.UnauthorizedAccessException: Access is denied. (Exception from HRESULT: 0x80070005 (E_ACCESSDENIED))
Publishing Feature activation failed. Exception: Microsoft.SharePoint.SPException: Provisioning did not succeed. Details: Failed to initialize some site properties for Web
at Url: ‘SITENAME’ OriginalException: Access is denied. (Exception from HRESULT: 0x80070005 (E_ACCESSDENIED)) —> System.UnauthorizedAccessException: Access is denied. (Exception from HRESULT: 0x80070005 (E_ACCESSDENIED))