Pages

Showing posts with label SharePoint 2010. Show all posts
Showing posts with label SharePoint 2010. Show all posts

January 3, 2017

Solving SharePoint error: The request uses too many resources



Scenario:
I was deleting a group of items in a SharePoint list. After selecting the items, I clicked 'Delete Item' from the ribbon but nothing happened! the items were not deleted, the page didn't refresh and not even single item moved to the site recycle bin. The UI didn't show any error message.

Below is excerpt from ULS logs:
 Name=Request (POST:{SiteUrl}/_vti_bin/client.svc/ProcessQuery)

 Begin CSOM Request ManagedThreadId=8, NativeThreadId=20404
 Original error: Microsoft.SharePoint.Client.ClientServiceException: The request uses too many resources.     at Microsoft.SharePoint.Client.ClientMethodsProcessor.Process()
RequestMessage: <Request xmlns="http://schemas.microsoft.com/sharepoint/clientquery/2009" SchemaVersion="15.0.0.0" LibraryVersion="15.0.0.0" ApplicationName="Javascript Library"><Actions>................... 

The RequestMessage part is very long to put here.


Digging for answers:
This error is from server side. Since I am doing item deletion from default OOB list view (which uses client-side object model), I decided to work on the Client.svc (from 15 hive: \ISAPI\Client.svc):

<%@ServiceHost language="c#" Service="Microsoft.SharePoint.Client.ClientRequestService, Microsoft.SharePoint.Client.ServerRuntime, Version=15.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" Factory="Microsoft.SharePoint.Client.Services.MultipleBaseAddressWebServiceHostFactory, Microsoft.SharePoint.Client.ServerRuntime, Version=15.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>

So I looked for the logic inthe assembly Microsoft.SharePoint.Client.ServerRuntime.dll.
Inside Microsoft.SharePoint.Client.ClientMethodsProcessor.Process() method:

int maxObjectPaths = this.m_serviceSurrogate.ClientCallableSettings.MaxObjectPaths;
int num = 0;
…
if (maxObjectPaths > 0 && num > maxObjectPaths)
{
       throw new ClientServiceException(Resources.GetString("ClientRequestExceedMaxResources"));
}

At run time, if number of total selected items are larger than 'ClientCallableSettings.MaxObjectPaths' then it will throw the error message internally, and the client side will just do nothing.

From PowerShell, I checked current value of 'MaxObjectPaths' property for target web application:
$WebApp.ClientCallableSettings.MaxObjectPaths
The returned value was 256 (which is the default value).

Okay, the immediate conclusion is that I can delete up to 256 (to be less than or equal to current value of MaxObjectPaths).. Let's test that:

Test: set MaxObjectPaths to 2 then try to delete 3 items only.
$WebApp.ClientCallableSettings.MaxObjectPaths = 2
$WebApp.Update()
Result: It failed with same error "The request uses too many resources" in ULS.

To understand why this happened, I needed to go back and recheck the error detail in more depth from ULS logs. 


Process Request Format & Analysis:
After careful inspection, I put the below format for RequestMessage property sent by client to Server to process:

<Request xmlns="http://schemas.microsoft.com/sharepoint/clientquery/2009" SchemaVersion="15.0.0.0" LibraryVersion="15.0.0.0" ApplicationName="Javascript Library">

<Actions>
<ExceptionHandlingScopeSimple Id="..">
<ObjectPath Id="3" ObjectPathId="2" />
<ObjectPath Id="5" ObjectPathId="4" />
<ObjectPath Id="7" ObjectPathId="6" />
<ObjectPath Id="9" ObjectPathId="8" />
<ObjectPath Id="11" ObjectPathId="10" />
<Method Name="MethodName" Id="12" ObjectPathId="10" />
</ExceptionHandlingScopeSimple>
…
</Actions>

<ObjectPaths>
<StaticProperty Id="2" TypeId="{TypeID}" Name="Current" />
<Property Id="4" ParentId="2" Name="Web" />
<Property Id="6" ParentId="4" Name="Lists" />
<Method Id="8" ParentId="6" Name="GetById"><Parameters><Parameter Type="String">{ListID}</Parameter></Parameters></Method>
<Method Id="10" ParentId="8" Name="GetItemById"><Parameters><Parameter Type="Number">ItemID</Parameter></Parameters></Method>
…
</ObjectPaths>

</Request>
 

The RequestMessage contains the required details of the operation that is requested by Client to be performed by Server.
It starts with 'ObjectPath' nodes under <ObjectPaths>. The highlighted parts in Yellow indicates the required SharePoint IDs. The first 4 nodes (in light Grey) are essential to know where target items are located. It starts with Item type, then web, then list. The actual items starts at the 5th node, they are represented by <Method> that sets the calling method 'GetById' with that item ID.
In other words there will be always 4 initial nodes followed by method nodes equal to number of items.
If everything works fine, then it will process the <Actions> section, where for every item (referred to by ObjectPathId parameter) it is required to run a specific method (MethodName for example: 'Recycle').


Conclusion:
Based on my tests & format analysis above, client batch operation can support a number of items equal to (ClitentCallableSettings.MaxObjectPaths - 4)
Example: If ClitentCallableSettings.MaxObjectPaths = 256 then we can delete up to 252


Solution:
1. Use PowerShell to check existing value of MaxObjectPaths property for target web    application:
     $WebApp.ClientCallableSettings.MaxObjectPaths


2. If total number of items (to be deleted or updated) > (MaxObjectPaths - 4) then set a larger value for MaxObjectPaths:
    $WebApp.ClientCallableSettings.MaxObjectPaths = $TotalItemsCount + $requiredDiff
    $WebApp.Update()

Example: to be able to delete 256 items in 1 batch, then set MaxObjectPaths to 260


Note:

·         Be aware for performance impact before setting MaxObjectPaths value.

 

November 29, 2016

How To Show Solution Name For Each Feature In SharePoint





The objective:
Ever occurred to you that you loose track of what solutions relates to what features enabled at site or site collection level? Yeah I've been in that situation too.
The objective is to add new field to Site features & Site Collection features page (/_layouts/ManageFeatures.aspx) showing a link of Solution name for each feature.

Introduction:
First, let's have a look for on urls of different pages:
Site features:         /_layouts/ManageFeatures.aspx
Site Coll. features: /_layouts/ManageFeatures.aspx?Scope=Site
WebApp features: /_admin/ManageWebAppFeatures.aspx?WebApplicationId={Id}&IsDlg=1
 (from CA -> select WebApp -> Manage Features)
Farm features:       /_admin/ManageFarmFeatures.aspx
 (from CA -> System Settings -> Manage farm features)

In this post, I am going to customize 'ManageFeatures.aspx' page only. However, the same procedure below can be applied to other pages. (Note: influenced by code from following post , I decided that I should start customizing my solution http://blogs.msdn.com/b/varun_malhotra/archive/2012/01/31/sharepoint-2010-get-solution-file-name-from-feature-activated.aspx).


OOB Page Details:
Let's first understand contents of ManageFeatures.aspx page and how it works:


- Fields: FeatureIcon(image), FeatureTitleDescription(Text), FeatureActiveButton(button), FeatureActiveState(text)


- Page calls a user control (~/_controltemplates/FeatureActivator.ascx) to render the table of features
<asp:Content ContentPlaceHolderId="PlaceHolderMain" runat="server">
 <wssuc:FeatureActivator runat="server" ID="featact" />
 <SharePoint:FormDigest runat=server />
</asp:Content>


- Page also calls another control ( ~/_controltemplates/FeatureActivatorItem.ascx) to do the feature logic
<AlternatingItemTemplate>
  <wssuc:FeatureActivatorItem
   DataItem='<%# Container.DataItem %>'
   AlternatingItem="true"
   runat="server"
/>


The feature logic is at code files:
- Microsoft.SharePoint.WebControls.FeatureActivator.cs
- Microsoft.SharePoint.WebControls.FeatureActivatorItem.cs


Customization Steps for SP2010 & SP2013:

1. First, make sure you backup the original manageFeatures.aspx page & user controls files (FeatureActivator.ascx & FeatureActivatorItem.ascx).


2. Make a copy for the following: page & user controls, then rename all with postfix with "Ex":
 ManageFeaturesEx.aspx, FeatureActivatorEx.ascx, FeatureActivatorItemEx.ascx

3. Do the following changes to edit 3 files:

- In ManageFeaturesEx.aspx file:
 Set the Src parameter to refer to FeatureActivatorEx.ascx
 <%@ Register TagPrefix="wssuc" TagName="FeatureActivator" src="~/_controltemplates/FeatureActivatorEx.ascx" %>

- In FeatureActivator.ascx file:

    1. Set the Src parameter to refer to FeatureActivatoritemEx.ascx
    <%@ Register TagPrefix="wssuc" TagName="FeatureActivatorItem" src="~/_controltemplates/FeatureActivatorItemEx.ascx"     %>

    2. Add new column header ("Solution") under <colgroup> add: <col width="10%" />

    3. Add new column content:
    *** For SP2010 ***
    Under <tr> add:       
      <th scope="col" id="FeatureSolution" class="ms-vh2" style="padding-bottom: 4px"><SharePoint:EncodedLiteral             runat="server" text="From Solution" EncodeMethod='HtmlEncode'/></th>

    *** For SP2013 ***
    Under <tr> add:       
      <th scope="col" id="FeatureSolution" class="ms-vh2-nofilter" style="padding-bottom: 4px"><SharePoint:EncodedLiteral         runat="server" text="From Solution" EncodeMethod='HtmlEncode'/></th>

- In FeatureActivatorItem.ascx file:
    1. Only for SP2013: First Add these 2 lines to import SharePoint namespaces
    <%@ Import Namespace="Microsoft.SharePoint" %>
    <%@ Import Namespace="Microsoft.SharePoint.Administration" %>

    2. insert the following code in page after the header tags & before first <td> tag:
    <script runat = "server">
        SPSite Site = SPContext.Current.Site;
        SPSolutionCollection FarmSolutions = SPContext.Current.Site.WebApplication.Farm.Solutions;
       
        private string getSolutionNameFromFeatureDef(SPFeatureDefinition featDef)
        {
        string result = string.Empty;
        Guid FeatureSolutionID = featDef.SolutionId;
        if (FeatureSolutionID != Guid.Empty)
        {
            SPSolution solution = FarmSolutions[FeatureSolutionID];
            if (solution != null)
            {
                result = solution.SolutionFile.DisplayName;
            }
        }
        return (result);
        }

        public string getSolutionName()
        {
        string result = string.Empty;
        try
        {
            Guid FeatureID = new Guid(this.FeatureId);
            SPFeatureDefinition CurrentFeatureDefinition;
            SPFeature CurrentFeature = Site.Features[FeatureID];
            if (CurrentFeature != null)
            {
                // feature is activated at site collection
                CurrentFeatureDefinition = CurrentFeature.Definition;
            }
            else
            {
                // feature is activated at Farm or other level
                CurrentFeatureDefinition = SPFarm.Local.FeatureDefinitions[FeatureID];
            }
            result = getSolutionNameFromFeatureDef(CurrentFeatureDefinition);
        }
        catch (System.Exception)
        {
            // do nothing when exception
        }       
        return (result);
       }
    </script>

    3. Then add a new <td> cell at the end of file:
      <td class="<% Response.Write(this.CssClass); %>" style="padding-top: 4px; padding-bottom: 4px; ">
            <table width="100%" cellpadding="0" cellspacing="0" border="0">
            <tr><td class="ms-vb2"><% Response.Write(getSolutionName());%></td></tr>
            </table>
    </td>


    Note: for SP2013 make sure to postfix any '_layouts/' with '15' to target the new hive


4. Copy the 3 files to hive (14 for SP2010 or 15 for SP2013) in all related WFE servers:
 - Copy controls FeatureActivatorEx.ascx, FeatureActivatorItemEx.ascx to \TEMPLATE\CONTROLTEMPLATES folder
- Copy page ManageFeaturesEx.aspx to \TEMPLATE\LAYOUTS folder

That's it! no need for IIS reset. Now you can enjoy having the solution info across all sites collection & site features across the farm.

Note: the solutions column will be empty when no wsp found for target feature (example: for OOB MS features that were stapled in with site definition). Also, solutions column will not support user solutions (sandboxed solutions).



May 11, 2016

SPSite constructor Exception The Web Application Could Not be Found


Description: When calling SPSite constructor

using (SPSite site = new SPSite(UrlString))
{
....
}

 The user will get the following FileNotFoundException:  
"The Web application at {url} could not be found. Verify that you have typed the URL correctly."
 
Given that the calling user is NOT a site collection admin or secondary admin. User has Owner read access on target site. User can access the site normally from browser.


Reason: I concluded that this is a low-level access issue. User does not have access to config db.


If you care to know how it happened in details then continue reading!

Digging for the error:
Okay, so you really wanted to know the details.. lets start by having a look from the behind the scenes at the code from Microsoft.SharePoint.dll:
 
The call starts from SPSite Constructors (with or without User token) where it tries to get local farm then pass it to another internal SPSite constructor:

.method public hidebysig specialname rtspecialname instance void .ctor (string requestUrl) cil managed
        {
                // Method begins at RVA 0x1e9b54
                // Code size 24 (0x18)
                .maxstack 8
                IL_0000: ldarg.0
                IL_0001: call class Microsoft.SharePoint.Administration.SPFarm Microsoft.SharePoint.Administration.SPFarm::get_Local()
                IL_0006: ldarg.1
                IL_0007: newobj instance void [System]System.Uri::.ctor(string)
                IL_000c: ldc.i4.0
                IL_000d: call class Microsoft.SharePoint.SPUserToken
Microsoft.SharePoint.SPSecurity::GetDefaultUserToken()
                IL_0012: call instance void Microsoft.SharePoint.SPSite::.ctor
(class Microsoft.SharePoint.Administration.SPFarm, class [System]System.Uri, bool,
class Microsoft.SharePoint.SPUserToken)

                IL_0017: ret
        } // end of method SPSite::.ctor



Check the highlighted lines. The SPFarm.Local will try to initialize a connection to local configuration
database (using .NET runtime security if it has permission), then return local farm of that db or null (if failed to read local config db). Internally, here is how get_Local() works:
SPConfigurationDatabase local = SPConfigurationDatabase.Local;

Since the account does not have access on config db, then SPFarm.Local returns null value. I also tested this part from a C# console using the same user account, calling SPFarm.Local returned null.

Back to SPSite constructor code. this constructor will pass the farm object to another internal instructor:

internal SPSite(SPFarm farm, Uri requestUri, bool contextSite, SPUserToken userToken)
                {
                        if (farm == null)
                        {
                                throw new FileNotFoundException(SPResource.GetString("WebApplicationLookupFailed", new object[]
                                {
                                        requestUri.OriginalString
                                }));
                        }
                        if (!requestUri.IsAbsoluteUri || (requestUri.Scheme !=
Uri.UriSchemeHttp && requestUri.Scheme != Uri.UriSchemeHttps))

                        {
                                throw new FileNotFoundException(SPResource.GetString("WebApplicationLookupFailed", new object[]
                                {
                                        requestUri.OriginalString
                                }));
                        }
                        ......
                        SPWebApplication sPWebApplication = SPWebApplication.Lookup(farm, requestUri, contextSite, out sPAlternateUrl, out sPSiteLookupInfo, out this.m_LookupRequiredContext);
                        if (sPWebApplication == null)
                        {
                                throw new FileNotFoundException(SPResource.GetString("WebApplicationLookupFailed", new object[]
                                {
                                        requestUri.OriginalString
                                }));
                        }
......

                }


From highlighted lines in code above, we can see that exception can be throw in 3 cases:
#1 When Farm object is null
#2 When Site uri argument is not absolute or the scheme is not either http nor https
#3 When Web application is null (when Web Application lookup fails with Alternate Url)
   
The reason in our case is #1 I believe. Check 1st highlighted line in Orange. The SPSite constructor will pass the local farm object to the internal SPSite constructor. Since the farm object is null, it will throw FileNotFoundError exception. The error message itself will be read from  “WebApplicationLookupFailed” resource key. This error message actually comes from 'Strings.cs' file.
As a quick test I used PowerShell to display the error message:

[Microsoft.SharePoint.SPResource]::GetString("WebApplicationLookupFailed")
Output:
The Web application at |0 could not be found. Verify that you have typed the URL correctly. If the URL should be serving existing content, the system administrator may need to add a new request URL mapping to the intended application.


The Lesson to be learned:

The user got a WebApplication no found exception, while the real exception is Access Denied in config db. Do not trust all exceptions to be straight forward, as SharePoint has its own way of interpreting stuff!




January 18, 2015

Fixing deploymet error: The feature is not a Farm Level feature and is not found in a Site level defined by the Url

If you have a SharePoint 2013 site that was migrated from SP2010 but the visual upgrade was not performed, then it will be on SP2010 UI mode as you can see in Fig #1 below (unlike the case of a brand new SP2013 or after the visual upgrade as in Fig #2).


Figure #1 -  Sharepoint 2013 with SP2010 UI



Figure #2 – SharePoint 2013 with SP2013 UI





So in SharePoint 2013 site with SP2010 UI mode, if you are deploying a feature (for example a visual web part) through Visual Studio or PowerShell then the following occurs:
  • The feature is scoped to "Site", and Activate on Default is set to true.
  • Active deployment configuration is default\
  • Solution will be added to farm
  • Feature will be installed on farm, and feature files will be copied to features folder in 15 hive (\15\TEMPLATE\FEATURES).
  • .Dll files will be deployed to GAC or local bin folder
  • User controls will be copied to control templates folder in 15 hive (\15\TEMPLATE\CONTROLTEMPLATES).
  • Feature is not added to site collection features page.
  • Enable-SPFeature command will fail with error message:
    The feature is not a Farm Level feature and is not found in a Site level defined by the Url [Site Collection Url].
  • The .webpart file will not be copied to Web Parts Gallery (_catalogs/wp) in target site collection.
  • Web part cannot be added to any page.

Solution:
Use CompatibilityLevel parameter in Install-SPSolution PowerShell cmdlet to deploy the solution in either or both 14 & 15 hives:

Install-SPSolution -identity SolutionName.wsp -GACDeployment -CompatibilityLevel{14,15} -WebApplication https://ServerName.Domain.com
Also, you can apply the CompatibilityLevel parameter to Enable-SPFeature cmdlet to activate individual features in either or both hives.