Updated on Dec 2015 – Newer version of this article for SharePoint 2013, SharePoint 2016, and SharePoint Online can be found here.
Updated on Jan 2013 – This article most relevant to SharePoint 2010 On-Premises custom development. Many of these best practices still valid for SharePoint 2013 On-Premises custom development especially full trusted solutions. This article does not cover new features like CSOM and REST API updates and Apps Model in SharePoint 2013. This article may not apply to SharePoint Online custom development best practices.
If you are new to SharePoint 2010 development, building custom solutions based on the SharePoint 2010 framework is never easy. Sometimes list of types of custom components you can build on top of SharePoint 2010 Foundation framework is overwhelming. For the novice or even for the experienced SharePoint developers, it would be easy to get lost into specifics of the SharePoint 2010 development. Every kind of custom SharePoint components like web parts, visual web parts, application pages, site pages, master pages, page layouts, content types, list definition, site definitions, workflows, event receivers, lists, content types, field types, etc. brings their own special challenge.
As a developer, as we focus on solving business problems with custom SharePoint solutions, sometimes it’s too late to realize that it would be great if you have known some of the best SharePoint development practices and hoping to assure that you are following industry best practices and building upgradable solution.
I am going to use this blog entry to compile some of the SharePoint 2010 development best practices I try to follow whenever I am customizing SharePoint environments using solutions and features framework. I am planning to update this page over the time.
- Although this is no brainer for seasoned SharePoint developers, novice will always tweak out of box files. Don’t ever change the files in the out of the box SharePoint Root (14-Hive) directory.
- Never build your SharePoint development environment on the host machine. Use the Virtual Machine instead. Virtualized environment promotes portability, playground as sandbox, and allows quick and easy way to snapshot the development environments.
- Leverage WSPs (solutions and feature framework) while deploying and packaging code from development to staging to production environment.
- Make sure solutions have proper consistent naming convention e.g. OrganizationName.BusinessSolution.<ProjectName>
- Make sure solutions have proper feature name and description. Feature name and description would be visible on the site collection and site features page.
- Make sure custom code is compiled and packaged in release mode.
- Use SPUtility, SPUrlUtility, and HttpUtility if you can. e.g. Use SPEncode to encode the HTML and URL encoding.
- Since URLs can change between different environments, use site.serverrelativeurl instead of site.url to build the URL in code. Additionally, whenever you are referencing site collection level libraries (e.g. style library), do not reference URLs with “/” as first character in the reference URL. “/” assumes top level site collection and it may not work in child level site collection. e.g. “/Style Library/XSL Style Sheets” will work fine in the top level site collection but will fail in the child level site collection. Instead of either use “Style Library/XSL Style Sheets” from HTML markup or use site.serverrelativeurl in the code to build full URL.
- Don’t forget to dispose the newly created SPWeb and SPSite objects. If you create an object using “new”, you must dispose it. (e.g. SPSite site = new SPSite(url) or SPWeb web = site.OpenWeb()). Although SPWeb and SPSite objects use minimal managed memory, it allocates substantial unmanaged memory. You must free up unmanaged memory allocated during creation of SPWeb or SPSite objects by disposing the objects. Best practice is to instantiate objects with “using” keyword in C#. (e.g. using (SPSite spSite = new SPSite(url))). Additionally, always run solution against SPDisposeCheck utility to ensure disposing all the objects properly before production deployment. (http://code.msdn.microsoft.com/SPDisposeCheck)
- Don’t dispose the SPContext.Current.Site or SPContext.Current.Web object. It will be disposed automatically by the runtime. e.g. Do not use “using” keyword with the object referenced through SPContext (e.g. don’t use using(SPWeb spWeb = SPContext.Current.Web))
- Don’t use SPContext.Current.Site or SPContext.Current.Web objects in the Feature Receiver to access current instance of SPWeb or SPSite . If you ever try to activate/deactivate features using PowerShell, SPContext would fail because it’s available only in the browser context. Instead use properties.Feature.Parent to access current instance of SPWeb or SPSite object. For Site collection level feature, it would return SPSite and for web level feature, it would return SPWeb object. (e.g. use using (SPWeb spWeb = (properties.Feature.Parent as SPWeb)))
- Plan to install SharePoint Manager 2010 from the codeplex. It is a SharePoint object model explorer and enables you to browse every site properties on the local farm by browsing through SharePoint Internals.(http://spm.codeplex.com/)
- Use SharePoint Developer Dashboard to Investigate the Page Performance bottlenecks. It gives detailed information on resource usage, performance, user interactions and error trapping. Use SPMonitoredScope code block to generate the custom logged counters on the Developer Dashboard. Please note that you can enable the Developer Dashboard at the farm level and never enable it in production environment.
- Use SPGridView instead of standard ASP.NET Gridview to inherit the SharePoint CSS, Look and Feel, and Column filtering mechanism. On other side, Use standard ASP.NET Gridview instead of SPGridView to full control over the tabular design and functionality.
- Use the List Event Receivers to execute the code immediately. Workflows can perform similar function but it will run as a timer job which may delay the code execution.
- Use SharePoint Site Property Bag to classify the sites and persist site level metadata. You can either use SPWeb.Properties (Microsoft.SharePoint.Utilities.SPPropertyBag Object) or SPWeb.AllProperties (System.Collections.Hashtable Object) or Site Property Bag Configuration Tool – http://pbs2010.codeplex.com/. SPWeb.Properties considered as legacy approach since it stores key and value in lowercase. SPWeb.AllProperties keeps casing of key and value intact. If you don’t care about the persisting case, plan to use older method SPWeb.Properties instead of newer method SPWeb.AllProperties. Here is the reason why – http://www.novolocus.com/2010/12/22/stupid-spweb-properties/
- Don’t build State Workflows in the SharePoint 2010 using Visual Studio 2010. State workflows may NOT be upgradable because they are not available in the .NET 4.0 which might be foundation framework for the next version of SharePoint.
- Use field controls on the WCM sites instead of web parts because you won’t have page history with web parts.
- For the list data access using server side object model, Use LINQ if you can, CAML if you must. Another argument is – Use CAML for fastest performance and LINQ for object oriented development.
- Do not instantiate SPWeb, SPSite, SPList, or SPListItem objects within a list event receiver. It would cause significant performance overhead due to additional round trips to the database and fail other registered event receivers during subsequence update calls. Instead retrieve the SPWeb or SPListItem from SPItemEventProperties. (e.g. use SPWeb web = properties.OpenWeb() or SPListItem item = properties.ListItem)
- Do not use SPList.Items while accessing list items using server side object model and try to avoid SPList.Items in a loop expression. SPList.Items iterates through all list items from all subfolders and all fields in the list item. To retrieve the list items, instead use SPList.GetItems(SPQuery query).
- Target farm level solutions to the specific web application instead of deploying to all web applications unless you are deploying new feature to all the applications in the farm. This way custom feature for the specific web application won’t available on site collection features page or site features page on all the web applications in the farm.
- Build Sandboxed solutions over farm level solutions for site collection specific custom solutions to balance business agility and IT stability. Understand the limitations of the sandbox solutions. Create site collection resource quota templates in the central administration. Another argument against sandbox solutions is it has resource quota points estimation issues for heavily collaborated sites.
- Plan to disable the SharePoint Designer at the farm level and enable at the web application and site collection level as needed.
- Instead of Custom Site Definition, use Web Template or Feature Stapling capabilities to add custom features on the out of the box site definition. I would also prefer Custom Coded Site Templates from scratch by creating site based on team or blank site template and activate features as needed. Also, word of caution – Never change out of the box site definition.
- Deployment discipline – During the deployment and retraction process while updating or upgrading custom solutions, please use the correct older version of WSPs to retract the solution before deploying or upgrading the custom code with newer version of WSPs. This would ensure activating or deactivating features reference correct version of WSPs.
- Although the CSOM, the REST interface, and the SharePoint ASP.NET Web services are all available when you develop server-side code, the use of these APIs in server-side code is only recommended for accessing data from another farm. Using the server-side object model for full-trusted solutions are more efficient and supports full API set than using any of the client-side APIs.
- Plan to reference common DLLs from GAC. Developers work on different solutions and local path structure referencing common DLLs (e.g. Microsoft enterprise library, SharePoint client side redistribuble etc.) from the Visual Studio project. I have seen common DLLs gets referenced with relative path requiring same structure for all the developers in team based development. One way to standardize referencing common DLLs are hosting them in GAC and reference GAC dlls from the Visual Studio project. This would ensure all the developers are referencing dll from same local path.
Hope it will be helpful.