December 18, 2013

Expand SPTreeView Node Automatically When Selected


Before:
After:


The standard behavior of SharePoint tree view control (SPTreeView) is that when you select a folder node it will not expand its children nodes. You must click the expand icon [+] in order to show the sub folders. Also, that is not exclusive, so when you click the expand [+] icons of another node folder, the tree will show it's children without collapsing the previous node folder.


The objective:

I wanted to customize the tree view navigation to combine the functionality of clicking the node title and clicking the expand icon so that user can expand nodes with less hassle. The user should only click a node folder title and the tree will automatically expand to show child nodes while other nodes will collapse.


How:

I'll use JQuery. The idea is when a node title is clicked then a post back occurs and there will be a RootFolder parameter in page Url indicating selected folder node, so we will call the javascript function associated with its exapnd [+] icon.

This is the markup for the SPTreeView in the page:

<SharePoint:SPHierarchyDataSourceControl id="doclibDataSource" runat="server" RootListId="a65a6e37-de92-496a-b896-5b976dff7b61"
RootWebId="277d98b7-be33-451f-9ed8-6691a5a72736" ShowFolderChildren="true" EnableViewState="false">

</SharePoint:SPHierarchyDataSourceControl>
<SharePoint:SPRememberScroll runat="server" id="TreeViewRememberScrollV4" onscroll="javascript:_spRecordScrollPositions(this);" style="overflow: auto">
<SharePoint:SPTreeView ID="doclibtreeview" runat="server" DataSourceID="doclibDataSource" EnableViewState="false" ExpandDepth="1" SelectedNodeStyle-CssClass="SelectedItemStyle">
</SharePoint:SPTreeView>
</SharePoint:SPRememberScroll>


Inject the following script in the master page or in CEWP. I added the SelectedItemStyle CSS style to make selected nodes more visible.


<style>
.SelectedItemStyle {
BORDER-TOP: 1px dotted; BORDER-RIGHT: 1px dotted; BORDER-BOTTOM: 1px dotted; BORDER-LEFT: 1px dotted; BACKGROUND-COLOR: #dddddd
}</style>

<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>

<script>

_spBodyOnLoadFunctionNames.push("customIBRTreeNav");

function customIBRTreeNav(){
var SelectedFolder = unescape(getUrlParameter('RootFolder'));
var ItemTitle = SelectedFolder.substring(SelectedFolder.lastIndexOf("/") + 1);
var LinkItem = jQuery('a[title="' + ItemTitle + '"]:not(:has(img))');
var IconItem = LinkItem.closest('td').prev('td').prev('td').find('a');// [+] & [-] icon
var IconItemHref = IconItem.attr("href");
var CustomTreeViewPopulate = new Function(IconItemHref); // create the function from string
CustomTreeViewPopulate.call(this);
}

function getUrlParameter(name)
{
  name = name.replace(/[\[]/,"\\\[").replace(/[\]]/,"\\\]");
  var regexS = "[\\?&]"+name+"=([^&#]*)";
  var regex = new RegExp( regexS );
  var results = regex.exec( window.location.href );
  if( results == null )
    return "";
  else
    return results[1];
}</script>


Note: remember to set the ExpandDepth parameter to value of '1' in the SPTreeView control. 
This is necessary to get the intended functionality. I didn't have time to implement the logic when ExpandDepth is 2 or more.. maybe later!


December 6, 2013

Issue: Starting a service crashes SharePoint site with unknown error


Issue:

After you stop a service (such as User Profile Synchronization or Search service) and try to start it again in Central Administration, the SharePoint 2010 site pages will crash with an unknown error.



Analysis:

Prior to the issue, the password was changed for the services account in SharePoint. However all services were working.

Searching the cascading numerous errors in ULS to find the root cause kept my head spinning for hours. I knew that issue was because of the password change in services account but couldn't spot where is the start point to fix.
Some of the error messages I found in IIS log:
- "Application pool 15f65d1adf954fa68aee81f7bcb9cec8 has been disabled. Windows Process Activation Service (WAS) encountered a failure when it started a worker process to serve the application pool."
- Another message is that the account may need batch logon permissions.

 then I had a clear image of what happened:

  1. The service (User Profile Synchronization service or Search service) tries to start
  2. Service fails to start because its application pool in IIS could not login 
  3. Since its application pool is down, it will bring down all the services that are running on it. If User Profile service is working on this application pool then it will stop. Also if Metadata service is working on this application pool then it will stop, and bring down the Profile service as well since User Profile depends on Metadata.
  4. All content on SharePoint pages (such as pages, web parts,..) requires a valid user login to display according to user permissions. Since User Profile service is down, current user cannot be verified and SharePoint shows unknown error.

I already made sure that that the service account has the necessary permissions and that services and service applications are setup correctly on CA. Also the application pool account is using the correct password.
Well, it didn't work! Every time I try to start the application pool in IIS it stops after couple of seconds. Agrrrrrr...

It appeared that the faulty application pool "15f65d1adf954fa68aee81f7bcb9cec8" in IIS becomes corrupted object and will not work.



Solution:

Relocate applications that are on corrupted application pool into another one with exact same settings.
First, make a backup for WFE and APP servers.
Depending on your current configurations, make the following changes in IIS in WFE and APP servers:

  1.      Create new AppPool “MetadataCustomAppPool” as copy of the corrupt AppPool but using new password  for service account
  2.      Move “metadata” and “Profile” applications from corrupt AppPool to   “MetadataCustomAppPool” AppPool.  This is useful when other service is down (and     subsequently its AppPool is down too), it will not affect the Metadata/User Profile and the   SharePoint site will continue to work.
  3.     If other service applications are in corrupt AppPool, then you can relocate them into MetaDataCustomAppPool or create a new AppPool for them as appropriate.
  4.      Restart IIS



November 14, 2013

How to make SPTreeView work on a custom page with 2 or more list views


The issue

I was reading the other day an article here on how to add an SPTreeView control to a list view page using SharePoint Designer 2010. This works fine on a library view page (for example: AllItems.aspx).
However, if you add another list view web part into the same list view page, or if you want to use the SPTreeView in a custom page then an issue appears. When user clicks on folder node the SPTreeView control will NOT stay in the same page but will redirect into the library root page (AllItems.apsx).



Analysis

I found very little info about this in the Internet, so decided to dig this up. I'll show here the details with an example. If you are interested keep reading, or you can go directly to solution section below.

The example setup:
  • Suppose we want a custom page to show 2 list views of the same library using different filters, and we want a tree view navigation to work for both of them whenever we click a folder.
  • I created a document library named 'Test Library Doc' and put some files and folders.


  • Created 2 list views for 'Test Doc Lib':
  1. Local view: Content Type is not Folder, and the Scope field is equal to Global
  2. Global view: Content Type is not Folder, and the Scope field is equal to Local
  • Added a custom web part page 'TestTreeView.aspx', added an SPTreeView control with its SPHierarchyDataScourceControl to the page using SPD2010. Make sure the RootListID and RootWebId are relevant.



Tests: (both on custom page TestTreeView.aspx)

Case 1:
Using SPTreeView with only 1 list view web part. Upon user click, each folder node will redirect to same page TestTreeView.aspx with corresponding folder level. Here is how 'Folder A' node is rendered:

<a title="Folder A" class="ctl00_PlaceHolderMain_doclibtreeview_0" id="ctl00_PlaceHolderMain_doclibtreeviewt1" href="javascript:_spNavigateHierarchy(this,'doclibDataSource','30:FolderNode:ef072b87-28a5-4db4-b82f-097c7ba329d3','\u002fTest Library Doc\u002fFolder A',true,'FolderNode')">

Case 2:
Using SPTreeView with 2 or more list view web parts. Upon user click, each folder node will redirect to the default page of library (example: AllItems.aspx) instead of our TestTreeView.aspx. Here is how 'Folder A'node is rendered:

<a title="Folder A" class="ctl00_PlaceHolderMain_doclibtreeview_0" id="ctl00_PlaceHolderMain_doclibtreeviewt1" href="javascript:_spNavigateHierarchy(this,'doclibDataSource','30:FolderNode:ef072b87-28a5-4db4-b82f-097c7ba329d3','\u002fTest Library Doc\u002fFolder A',false,'FolderNode')">



I tried to override _spNavigateHierarchy() method & inserted our custom page TestTreeView.aspx as the url parameter to force the redirect..but it didn't work. This is due to how the tree view nodes internally works as you will see below.


Digging on the front-end:


One of the arguments (highlighted above in test cases 1 & 2) caught my attention, it's called 'listInContext'. The _spNavigateHierarchy() definition is inserted by the SPHierarchyDataSourceControl in its onLoad event:

<script type=\"text/javascript\"> \r\n//<![CDATA[\r\nfunction _spNavigateHierarchy(nodeDiv, dataSourceId, dataPath, url, listInContext, type)  {\r\n   CoreInvoke('ProcessDefaultNavigateHierarchy', nodeDiv, dataSourceId, dataPath, url, listInContext, type, document.forms." + this.Page.Form.ClientID + ", \"" + SPEncode.ScriptEncode(this.ConstructSamePageQueryString()) + "\", \"" + SPEncode.ScriptEncode(str) + "\");\r\n\r\n}\r\n//]]>\r\n </script>

When we click a folder node,  the following call sequence starts:
_spNavigateHierarchy() -> CoreInvoke() -> ProcessDefaultNavigateHierarchy() in Core.js file

function ProcessDefaultNavigateHierarchy(g,e,d,b,c,j,i,h,f){
    ULSrLq:;
    if(typeof _spCustomNavigateHierarchy=="function")_spCustomNavigateHierarchy(g,e,d,b,c,j);
    else if(c==false)top.location=b;
    else{
        var a=document.createElement("INPUT");
        a.type="hidden";
        a.name="_spTreeNodeClicked";
        a.value=d;
        i.appendChild(a);
        var k="?RootFolder="+escapeProperly(b)+h+"&"+g_AdditionalNavigateHierarchyQString;
        _SubmitFormPost(f+k);
        return false
    }


Inside ProcessDefaultNavigateHierarchy(), the logic is as this:
If the 'islistInContent' flag is false then set the page location to the root page of current library and eventually redirect to the library root page (i.e AllItems.aspx). Otherwise, if the islistInContent flag is true, then eventually redirect to our custom page (TestTreeView.aspx).

Now we need to find out why listInContext parameter was set to false in test case 1.


Digging more on the back-end:


Let's have a look on how the SPTreeView is being internally rendered inside Microsoft.SharePoint.dll
In Microsoft.SharePoint.Navigation.SPHierarchyNode.cs I found NavigateUrl() method representing a tree node click. The highlighted portion is the important part.

public string NavigateUrl

        {

            {
                string str = "javascript:_spNavigateHierarchy(this,";
                return (((((str + "'" + this.DataSourceControlName + "','") + this.Path + "','") +
SPHttpUtility.EcmaScriptStringLiteralEncode("/" + this.m_url)) + "'," + ((this.m_ds.IsSingleListViewPage &&
this.IsContextListNode) ? "true" : "false")) + ",'" + this.m_type + "')");
            }
        }



According to internal code, 'IsSingleListViewPage' member returns True when there is only 1 web part (either data view or xslt list view) in current page. 'IsContextListNode' property returns True only within a list context and there is a valid list ID.
So, as long as we use 2 list view web parts or use a custom page, then listInContext parameter in NavigateUrl() will always get the value of 'False'.



Solution:

I Wrote a JQuery script to force change the listInContext flag value from 'False' to 'True' for every rendered tree view folder node, then insert this script into a CEWP in our custom TestTreeView.aspx page:

<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>

<script>

_spBodyOnLoadFunctionNames.push("IbrTreeView");

function IbrTreeView() {

$("a[href*='javascript:_spNavigateHierarchy']")
.each(function()
{
this.href = this.href.replace("false", "true");
});
}

</script>


And it works!
When user clicks 'Folder A' folder node, the 2 view web parts will show underlying filtered contents on the same TestTreeView.aspx page. No more redirecting to AllItems.aspx.




Note:
Remember your page should only contain list view web parts of the same library. Otherwise user will witness inconsistencies/errors when clicking on tree nodes because SPTreeView may redirect to a folder that exist in library of 1st web part but does not exist in library of the 2nd web part.


I hope people find this useful :)

Ibraheem

November 6, 2013

Styling The Folders In Doc Lib Using JQuery and CSS


Objective:

In your SharePoint site, sometimes you need to stylize how the folders look like so that they no longer reflect the typical folder hierarchy layout. You can use a new image, color and font style in a specific document library view or in a web part page 


For example:
  • We want to replace folder icon with a custom image
  • We want the title font to be bold and with larger size


How to:


First let's prepare url to the new folder icon file. I uploaded "fact.gif" into Images library:
        http://{YourServerName}/publishingImages/fact.gif



Since we don't want to affect the entire SharePoint farm, we will use JQuery script to target specific page. You can use the script by registering the script file using ScriptLink control, or by putting the follwoing script inside a Content Editor Web part (CEWP).



1. To change the folder type icon only:


<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>

<script>
_spBodyOnLoadFunctionNames.push("changeFolderUI");

function changeFolderUI() {
jQuery("a[href*='?RootFolder=']").find("img").attr("src", "http://{YourServerName}/publishingImages/fact.gif");
}

</script>





2. To change the folder name and add icon to it:

(This can be useful when hiding the Type field, allowing only folders to have icons in Name field)

<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script><script>

_spBodyOnLoadFunctionNames.push("changeFolderUI");

function changeFolderUI() {
jQuery("a[href*='?RootFolder=']:not(:has(img))")
.css("font-weight", "bold")
.css("font-size", "16px")
.before("<img alt='arrow' src='{YourServerName}/publishingImages/fact.gif'/>");

}</script>




You can also step forward and apply multiple custom styling into folders depending on a folder name.
Have fun!

August 29, 2013

How to make a mandatory file attachment in list forms


Objective:
Enforce the user to upload a mandatory file attachment whenever he/she creates/edits a SharePoint list item. This can serve as a part of validation process.
 
Analysis:

First, let’s see how attachments are added to the form.
When you attach files in list forms, the attachments part will appear as a row for each file item:



When hitting F12 in IE, you will notice that files are fitted inside spans in the attachments table:

Solution:

The idea is to override the PreSaveAction() method and iterate through span elements inside the attachments table to check if each item meets our rule for required file. The SharePoint list item will not be save until the PreSaveAction() returns true value indicating there is at least one attachment matching the required criteria.

For example: we want the file to include the phrase "RequiredFormName", with ".docx" as file extension.

In your NewForm.aspx or EditForm.aspx, add a CEWP amd insert the following code into it:
<script>

function strEndsWith(str, suffix) {
return str.match(suffix+"$")==suffix;
}

function PreSaveAction() {
var attachment = document.getElementById("idAttachmentsTable");
var linkname;
var phrase1 = "RequiredFormName";
var phrase2 = ".docx";


// no attachment files
if (attachment == null || attachment.rows.length == 0)
{
document.getElementById("idAttachmentsRow").style.display = 'none';
alert("No attachments found. Please attach the required file.");
return false;
}

else
{
// searching in current uploaded and selected files
var Links= document.getElementById('idAttachmentsTable').getElementsByTagName('span');
for (var i = 0, l = Links.length; i < l; i++)
{
                                linkname = Links[i].textContent || Links[i].innerText;

                                linkname = linkname.toLowerCase();

                                phrase1 = phrase1.toLowerCase();

phrase2 = phrase2.toLowerCase();

if (linkname.indexOf(phrase1) != -1 && strEndsWith(linkname, phrase2))
{
                                                // required attachment found
return true;
}
}

// required attachment is not available
alert("Please attach the required file.");
return false;
}
}
</script>


You can replace the highlighted portions 1 & 2 strings with your custom file name & extension respectively.

Have a nice day!

July 14, 2013

Asp:HyperLinkField Gives Undesirable URL

Problem:

When using the ASP.NET HyperLinkField to display the SharePoint Hyperlink field, the HyperLinkField will concatenate the web address (URL) with a comma, a space and then the description.

<asp:HyperLinkField HeaderText="Detail" DataNavigateUrlFields="Detail" Text="Detail" />

The redundant portions are highlighted in Yellow.

Example1:

Result link: http://sptest/Site1/Pages/MyRequest.aspx?RequestID=2/22/2013 2:35:06 PM, View



Example2:

Result link on GridView:   http://www.google.com,%20http//www.google.com



Solution:

Replace the HyperLinkField with a TemplateField control. The TemplateField control will host a hyperlink control where it manipulate the NavigateUrl parameter to extract only the actual URL before the comma ‘,’ from the SharePoint Hyperlink field.

Example:
<asp:TemplateField HeaderText="Detail">
<ItemTemplate>
<asp:HyperLink ID="HyperLink2" runat="server" NavigateUrl='<%# ((string)Eval("Detail")).Split(new string[]{","}, StringSplitOptions.None)[0] %>' Text="View" Target="_blank" />
</ItemTemplate>
</asp:TemplateField>


June 10, 2013

Error: site template requires that the Feature be activated in the site collection

Scenario:
You want to create a site template and use it across your environments such as different site collections. In source Site Collection, you create a site and add content such as web parts, lists..etc. You save that site as a template. In destination Site Collection, you upload that template into Solution Gallery and activate it. Then you try to create a site based on the template, but it fails with the error:

The site template requires that the Feature {FeatureID} be activated in the site collection


The quick solution is go to Site Settings -> Site Collection Features and activate the missing feature then try again. Easy huh?
It depends!.. The problem arise when the missing features are not available in your destination environment such as a 3rd party solution that was installed only in source environment.
An alternative is to abandon this site template, and create a fresh site on the destination site collection to ensure that all features are available before creating the template to be used on the destination. This is only good when the site template is not complex to re-create such as when only small amount of customization had applied to source site. But recreating a full customized site that contains a lot of custom lists and web parts will take long hours or days. Another alternative is to go low-level, fix the template and make it work!


Error Analysis:

Let's first see what's happening. Digging for error details in ULS logs show us this:


SPException thrown: Message: The site template requires that the Feature {eb657559-be37-4b91-a369-1c201183c779} be activated in the site collection.. Stack:    
at Microsoft.SharePoint.Utilities.SPUtility.ThrowSPExceptionWithTraceTag(UInt32 tagId, ULSCat traceCategory, Str
ing resourceId, Object[] resourceArgs)     
at Microsoft.SharePoint.SPWebTemplateElement.VerifyFeatures(XmlNodeList xmlNodeFeatures, SPWe
b applyTemplateToThisWeb, Boolean checkIsFeatureActivatedInSiteCollection)     
at Microsoft.SharePoint.SPWebTemplateElement.VerifyFeaturesInWebTemplate(SPWeb applyTemplateToThisWeb)     
at Microsoft.SharePoint.SPWeb.LoadFeatureWebTemplateContent(SPFeatureWebTemplate featureWebTemplate)     
at Microsoft.SharePoint.SPWeb.ApplyWebTemplate(String strWebTemplate)     
at Microsoft.SharePoint.Solutions.AddGallery.AddGalleryWebPart.CreateSite()
..

Let's have an insider look at the Microsoft.SharePoint.DLL. The following is the code for VerifyFeatures() method in SPWebTemplateElement.cs class file:

private void VerifyFeatures(XmlNodeList xmlNodeFeatures, SPWeb applyTemplateToThisWeb, bool checkIsFeatureActivatedInSiteCollection)
        {
            if ((xmlNodeFeatures != null) && (xmlNodeFeatures.Count != 0))
            {
                foreach (System.Xml.XmlNode node in xmlNodeFeatures)
                {
                    XmlElement element = (XmlElement) node;
                    XmlAttributeCollection attributes = element.Attributes;
                    if (attributes != null)
                    {
                        System.Xml.XmlAttribute attribute = attributes["ID"];
                        if (attribute != null)
                        {
                            Guid guid = new Guid(attribute.Value);
                            SPFeatureDefinition definition = SPFarm.Local.FeatureDefinitions[guid];
                            if (null == definition)
                            {
                                definition = applyTemplateToThisWeb.Site.FeatureDefinitions[guid];
                            }
                            if (null == definition)
                            {
                                SPUtility.ThrowSPExceptionWithTraceTag(0x67323467, ULSCat.msoulscat_WSS_FeaturesInfrastructure, "CannotFindFeatureInstalledSpecifiedInWebTemplate", new object[] { guid.ToString("B") });
                            }
                            if ((checkIsFeatureActivatedInSiteCollection && !applyTemplateToThisWeb.IsRootWeb) && (applyTemplateToThisWeb.Site.Features[guid] == null))
                            {
                                SPUtility.ThrowSPExceptionWithTraceTag(0x67323468, ULSCat.msoulscat_WSS_FeaturesInfrastructure, "CannotFindFeatureActivatedSpecifiedInWebTemplate", new object[] { guid.ToString("B") });
                            }
                        }
                    }
                }
            }
        }


The code reveals that it iterates against all features in the template, and is checks if each feature  is installed then checks if it's activated. The highlighted code in Yellow shows where the error message is being thrown.
In our case we are missing a feature whose ID is: eb657559-be37-4b91-a369-1c201183c779, but  are there other missing features I should worry about? Let's open the template itself.

1. Either import the web template .wsp file using Visual Studio (using the ‘Import SharePoint Solution Package’ project option), or convert the .WSP into .CAB then extract the solution folder.
2. Go to ONet.xml (in Web templates -> Name Template)
3. In <Configurations> section, search inside <SiteFeatures> for missing features in your environment


The Nintex Worklfow solution was installed in my test source Site Collection (but not on destination).
I activated two 3rd party features on Site Collection level. The SiteFeatures section in ONet.xml has the following:
  • "Nintex Workflow 2010" with an ID: 0561d315-d5db-4736-929e-26da142812c5,
  • "Nintex Workflow 2010 Web Parts" has ID: eb657559-be37-4b91-a369-1c201183c779
  • and "NintexWorkflowContentTypeUpgrade" with ID: 86c83d16-605d-41b4-bfdd-c75947899ac7
The Nintex Workflow solution is not installed on the destination site collection, and hence these features cannot be installed/activated there.

Note: to know if the missing feature belongs to SP2010 OTB, then check if it exists in this list here.

So here is what's happening:

- the template .wsp file comes with a number of feature IDs that were part of the site collection and site when template created on source environment.
- When the template is installed & activated on destination environment, it tries to reference these features. If one feature does not exist (not installed) or not activated then an SPException error will be thrown.
- As we saw in verifyFeatures() method, the code throws an exception at the first feature missing and abort the site creation but will not give a list of other missing features. This is a drawback in design because it makes it difficult for the Administrator to fix it.


Solution:
Comment out or delete the entries of missing features.

  1. Open the template's ONet.xml to comment or delete every missing feature whether in SiteFeatures or in WebFeatures sections that you cannot activate in your environment, until the resulting template is workable.
  2. Build the project in VS to produce new web template, or repackage the folder into .CAB then save as .WSP file.

Note: If we comment only the first feature, save the template file and upload to Solutions Gallery then create the site then we see a similar error but this time it is regarding a different feature with ID: 86c83d16-605d-41b4-bfdd-c75947899ac7
Which is the next missing feature in line as you can see in the ONet.xml image above.


After you complete the 'cleaning work', your template can now work as charm and the new site was created successfully on destination site collection :)



May 17, 2013

Performance problem: SharePoint site is very slow


Performance Problem:
SharePoint 2010 Server site and Central Admin are unrealistically too slow (16 seconds or more) to open in browser, without showing any error. You added much more server hardware resources (CPU, RAM and HDD) but this solution fails to improve performance.


Analysis:
In IE, hit F12 key and found that the site home page took 73 seconds to load!


In Central Admin, click on the Health Analyzer to find an interesting item in the performance section: “Application pools recycle when memory limits are exceeded.”





According to this Microsoft article here:
Application pools recycle because memory limits have been enabled and exceeded. Recycling based on memory limits is not usually necessary in a 64-bit environment, and therefore recycling should not be enabled. Unnecessary recycling can result in dropped requests from the recycled worker process and slow performance for end users who are making requests to the new worker process.

In faulty server -> IIS Manager -> Application Pools -> select the ‘SharePoint – 80' -> right-click -> click Recycling. We see the following 2 values:
·         Virtual memory usage (in KB): is checked to use 1024 KB
·         Private memory usage (in KB): is checked to use 1024 KB


Cause:
Apparently the application pool (SharePoint – 80) is recycling each time it reaches the memory limit as set above to 1024 KB. This happens many times during page loading so the total time needed to load the page is too long.


Solution:
Follow this procedure:
1.   Current user account must be a member of the Farm Administrators group.
2.   Identify the failing server(s) and repeat the following steps on each failing server
[Central Administration -> Monitoring -> click Review problems and solutions, and then find the name of the server in the Failing Servers column, example: SharePoint - 80].
3.   Current user account must be a member of the Local Administrators group on each server in step 2 above.
4.   In faulty server -> IIS Manager -> Application Pools -> select the ‘SharePoint – 80' -> right-click -> click Recycling. Clear the 2 check boxes of Virtual memory usage (in KB) and Private memory usage (in KB) -> click Next -> click Finish. (Repeat this step for all AppPools of slow WebApps).




Open the site again, and now it’s really fast!


May 8, 2013

Site creation error: the folder does not exist



I have a SharePoint 2010 team site which has a doc lib called "Process Deliverables" and it contains folders with numbered names:


'0.SOW – Charter'
'1.Review Decision Report'
'2.Final Deliverables'

I saved this site into a template with its content successfully. When trying to create a site based on the template, it throws an error:
"Adding properties to the folder with url {..} failed while activating feature, the folder does not exist."

The url here is: ‘Process Deliverables/0.SOW – Charter’


Analysis:
I renamed the first folder '0.SOW – Charter' into '0_SOW – Charter' (without quotes). Then saved the site as a template and tried to create a site based on it. It threw a different error with similar message:


Here the url is: 'Process Deliverables/1.Review Decision Report'. This means the first folder passed successfully but the next folder item in the library fails.


Cause & Solution:
Special characters such as " # % & * : < > ? \ / { | } ~ . generally cannot be used in folder names. 
A complete list of these characters here.
In our case: the dot (.) is allowed but must be not consecutively used neither at the start nor the end of name. However, for some reason it is appearing to be causing the error here. Rename your folder if they have any of the above including the dot, example:

'0_SOW – Charter'
'1-Review Decision Report'
'2) Final Deliverables'


Now save your site as a template and create sites happily!







May 4, 2013

Custom values on Choice column - Part 2


In Part 1 here of this article, we understood how the default choices work in OTB Create Column page (FldNew.aspx) in SharePoint 2010.
Now, its time to start the fun. Let's see examples of how we can show custom choice values:

First, remember to always make a backup copy of any OTB file before customizing it.

Example 1: Change static text values in resource file
Open the wss.en-US.resx (located in C:\inetpub\wwwroot\wss\VirtualDirectories\80\App_GlobalResources directory) using notepad or Visual Studio. Search for the keys, and replace the default values with your custom values such as (X, Y, and Z).


And this is how it will look like when creating new column:


There are only 3 keys to be used here. The downside of changing values for these 3 keys is that this will impact other pages, for example these keys are used in qstedit.aspx page used in survey lists. 
You can create new keys with custom values inside wss.en-US.resx and reference them through a a GetGlobalResourceObject()  in FldNew.aspx page.


Example 2: Custom static choices on page:
You can define your static strings directly without the need to resources file.
Edit FldNew.aspx, and replace the whole original inline code (highlighted yellow portion in Part 1) with this:

SPHttpUtility.HtmlEncode(
            "January" + "\r\n" + "Febraury" + "\r\n" + "March"+ "\r\n" +
            "April" + "\r\n" + "May" + "\r\n" + "June" + "\r\n" +
            "July" + "\r\n" + "August" + "\r\n" + "September" + "\r\n" +
            "October" + "\r\n" + "November" + "\r\n" + "December"
            ,Response.Output);


And this is how it will look like:



Example 3: Custom dynamic strings:
We can provide list of numbers from 0 to 9. Put the following code instead of the inline code (highlighted yellow portion in Part 1) in page. Set the rows parameter inside the textarea tag to expand the choices box to show more values as required.

        string ChoicesTxt = "0";
       
        for (int i=1; i<10; i++)
            ChoicesTxt += "\r\n" + i.ToString();
       
       // write the choices string into idChoices control on page
       SPHttpUtility.HtmlEncode(ChoicesTxt,Response.Output);

 And it will like this:


Example 4: Custom data from SharePoint list:
Create a custom list named "MyChoices" and add your choice values in Title field. Adjust the permissions to make it readable by all farm users or elevate the privileges through code. Replace the idChoices inline code (highlighted yellow portion) with the following:


        string ChoicesTxt = "";
        bool  _CustomChoicesError = false;
       
        try
        {
            SPWeb web = SPContext.Current.Web;
            SPList MyChoicesList = web.Lists.TryGetList("MyChoices");
            if (MyChoicesList != null)
            {
                // if lists exists, read all the items
                SPListItemCollection MyChoices = MyChoicesList.Items;
                foreach (SPListItem choice in MyChoices)
                {
                    ChoicesTxt += choice.Title + "\r\n";  
                }
            }
            else
                _CustomChoicesError = true; // list does not exist
        }
        catch (Exception ex)
        {
            _CustomChoicesError = true;
        }
       
        // in case of error, revert back to original choices
        if (_CustomChoicesError)
            ChoicesTxt = "Enter Choice #1\r\nEnter Choice #2\r\nEnter Choice #3\r\n";
       
        // write the choices string into idChoices control on page
        SPHttpUtility.HtmlEncode(ChoicesTxt,Response.Output);

The list (left), and how the values will look like (right):



If the 'MyChoices' list is deleted or an error occurred during data retrieval, then the page will display the original values.
Note: When you create a column using custom choice values, change value of any of the items temporarily and then undo the change. This is to trigger clearOutDefaultWithCheck() for the default value control to show the first value (its default behavior is to take its value from the resources files). Also you can do this by adding more code to handle this.


I hope you enjoyed with these ideas about customizing the choice values across your farm.