SharePoint Dragons

Nikander & Margriet on SharePoint

Tag Archives: Nikander Bruggeman

SharePoint 2013 on demand loading pattern

SharePoint has a JavaScript on-demand loading library, the SP.SOD library (more info on https://msdn.microsoft.com/en-us/library/office/ff410742(v=office.14).aspx). We find the following pattern useful to ensure that a custom JavaScript library called MyCustomLib.js is only loaded once and on demand. So in the pattern below, MyCustomLib.js is only loaded when SP.SOD.executeFunc() is executed.

RegisterSod(MyCustomLib.js’, ‘/sites/ OurTestSite/Style%20Library/Javascript/MyCustomLib.js’);

RegisterSod(AnotherCustomLib.js’, ‘/sites/OurTestSite/Style%20Library/Javascript/AnotherCustomLib.js’);

RegisterSodDep(“MyCustomLib.js”, “SP.js”);

RegisterSodDep(“MyCustomLib.js”, ” AnotherCustomLib.js”);

SP.SOD.executeFunc(MyCustomLib.js’, null, function () { LoisAndClark.CustomApplication.MyCustomLib.init(); });

Advertisements

How to create an OfficeDev PnP Provisioning engine extensibility provider

The OfficeDev PNP provisioning engine (https://github.com/officedev/pnp-sites-core) is able to create an XML template based on a given SharePoint site and then use that XML template to create new sites. Ootb, the provisioning engine contains a considerable amount of stuff it can do as detailed in the PNP provisioning schema (https://github.com/OfficeDev/PnP-Provisioning-Schema/blob/master/ProvisioningSchema-2015-12.md). The provisioning engine allows you to define extension points that allow you to add custom steps to the provisioning process, and in this article we’ll explain how to do it. 

First of all, it’s quite possible to get the OfficeDevPNPCore15 (for SharePoint 2013 on prem) or OfficeDevPNPCore16 (for SharePoint Online) NuGet packages and use the provisioning engine like that. We’ve found that there’s tremendous value in being able to step through and debug source code, so unless you’ve got a tool that allows you to debug 3rd party assemblies on the fly within Visual Studio we far more prefer to add the OfficeDevPnP.Core project itself to our own provisioning tool and add a project reference to it so we have access to all source code. You can either obtain the source code by creating a project based on OfficeDevPnP.Core.dll (for example, via Telerik JustDecompile at http://www.telerik.com/products/decompiler.aspx) or get it directly by cloning it from the GitHub repository. This allows you to get much needed insights into the inner workings of the provisioning engine.

When building an extensibility provider, we’ve used 2 sources:

– The succinct article at http://www.erwinmcm.com/using-an-extensibility-provider-with-the-pnp-provisioning-engine/

– The PNP provisioning schema at https://github.com/OfficeDev/PnP-Provisioning-Schema/blob/master/ProvisioningSchema-2015-12.md

The process of building an extensibility process goes like this:

1. Create a custom provider class that implements the IProvisioningExtensibilityProvider.

2. Add a custom provider section to the XML template.

3. Implement the logic of the custom provider.

The C# code of a custom provider class looks like this:

using OfficeDevPnP.Core.Framework.Provisioning.Extensibility;

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using System.Threading.Tasks;

using Microsoft.SharePoint.Client;

using OfficeDevPnP.Core.Framework.Provisioning.Model;

using System.Xml.Linq;

namespace MyTest.Providers

{        

    public class CustomProvider : IProvisioningExtensibilityProvider

    {

        public void ProcessRequest(ClientContext ctx, ProvisioningTemplate template, string configurationData)

        {

        }

    }

}

Then, you need to adjust the XML generated by the provisioning engine and, if it’s not already there, add a custom <pnp:Providers> section. The <pnp:Providers> section needs to be placed within the <pnp:ProvisioningTemplate> section, and although the exact position doesn’t really seem to matter we place it pretty close to the end of the <pnp:ProvisioningTemplate> section. The <pnp:Providers> needs two attributes:

– Enabled, this is true or false and allows you to temporarily disable a custom provider.

– HandlerType, which expects the FQDN of the code that will be executed once the provisioning engine comes across this XML. It expects the following info: {Namespace + class name of extensibility provider}, {Assembly name}, {Version}, {Public key token, if the assembly is strong named}.

Within the <pnp:Providers> section, you can place anything you like as long as it’s valid XML. The following XML fragment is a minimal provisioning template that just creates a web property bag entry and executes a custom extensibility provider: 

<?xml version=”1.0″?>

<pnp:Provisioning xmlns:pnp=”http://schemas.dev.office.com/PnP/2015/12/ProvisioningSchema“>

  <pnp:Preferences Generator=”OfficeDevPnP.Core, Version=2.2.1603.0, Culture=neutral, PublicKeyToken=3751622786b357c2″ />

  <pnp:Templates ID=”CONTAINER-TEMPLATE-[GUID]”>

    <pnp:ProvisioningTemplate ID=”TEMPLATE-[GUID]” Version=”1″>            

      <pnp:Providers>

        <pnp:Provider Enabled=”true” HandlerType=”MyTest.Providers.CustomProvider, MyTest, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null”>

          <pnp:Configuration>

            <MyProviderConfiguration id=”SampleConfig” xmlns=”http://schemas.loisandclark.eu/MyProviderConfiguration“>

              <ChildNode Attribute=”value”>TextContent</ChildNode>

            </MyProviderConfiguration>

          </pnp:Configuration>

        </pnp:Provider>

      </pnp:Providers>

      <pnp:PropertyBagEntries>

<pnp:PropertyBagEntry Key=”lois” Value=”clark” Overwrite=”true” />

      </pnp:PropertyBagEntries>  

    </pnp:ProvisioningTemplate>

  </pnp:Templates>    

</pnp:Provisioning>

You can’t exert fine grained control over the exact execution point in the provisioning pipeline, but all extensibility providers are executed sequentially and almost at the end of the provisioning pipeline. Currently, only WebSettings (containing settings for the current web site such as a SiteLogo and Master page URL, see https://github.com/OfficeDev/PnP-Provisioning-Schema/blob/master/ProvisioningSchema-2015-12.md#websettings) and PersistTemplateInfo (info about the provisioning template that gets persisted in a web property bag entry) are executed after your extensibility providers.

So what’s left to do is provide an implementation that of the ProcessRequest() method of the extensibility provider. It gets passed the SharePoint context and gets access to the XML in the custom <pnp:Provider> section. Your code will have to process that config info and use the current web to do something useful. The following code is a valid implementation:

using OfficeDevPnP.Core.Framework.Provisioning.Extensibility;

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using System.Threading.Tasks;

using Microsoft.SharePoint.Client;

using OfficeDevPnP.Core.Framework.Provisioning.Model;

using System.Xml.Linq;

namespace MyTest.Providers

{        

    public class CustomProvider : IProvisioningExtensibilityProvider

    {

        public void ProcessRequest(ClientContext ctx, ProvisioningTemplate template, string configurationData)

        {

            ClientContext clientContext = ctx;

            Web web = ctx.Web;

            string configurationXml = configurationData;

            XNamespace ns = “http://schemas.somecompany.com/MyProviderConfiguration“;

            XDocument doc = XDocument.Parse(configurationXml);

            string id = doc.Root.Attribute(“id”).Value;

            var childNode = doc.Root.Descendants(ns + “ChildNode”).FirstOrDefault();

            if (childNode != null)

            {

                string innerValue = childNode.Value;

                string attr = childNode.Attribute(“Attribute”).Value;

            }

        }

    }

}

Concluding, this means the extension points in the provisioning process aren’t exactly great, but it’s easy to do and at least you get the correct SharePoint context for free and have the opportunity to store all config info in a single place.

Bug in January 2016 CU for SharePoint 2013: adjusting external links in site pages

There’s a bug in the January 2016 CU where the CU erroneously updates external links. On a site page, we have a link to an external JavaScript library placed on a CDN like this:

· //cdn.ourcompany.com/js/jquery/jquery.js

After the CU is done “fixing” it, this link has become an internal one:

· /js/jquery/jquery.js

Because of that, the page no longer is able to find the javascript file and the page fails. Links explicitly including the protocol are not molested in this way, so http//cdn.ourcompany.com/js/jquery/jquery.js remains http//cdn.ourcompany.com/js/jquery/jquery.js after CU installation. Let’s hope this bug is fixed in future updates, since we really want to leave out explicit protocols (like so: //cdn.ourcompany.com/js/jquery/jquery.js). We also would like the CU not to try to be too smart and stay away of the contents of our site pages. Btw, it also seems that the CU doesn’t touch similar references in page layouts.

SharePoint Debugging: Not without a trace

We’re always quite interested to see how other peoply try to solve SharePoint issues and thought it would be interesting to share a recent experience with MS support. In a case were list items got corrupted after a migration, MS support was interested in the following:

– An HTTP trace retrieved via Fiddler taken while the issue is reproduced via the browser.

– Relevant ULS log files.

– A memory dump of the SharePoint process retrieved via tttracer taken while the issue is reproduced.

To us, the latter choice is the most interesting one. Tttracer.exe refers to the Microsoft Time Tracel Tracing Tool (see http://www.thewindowsclub.com/microsoft-time-travel-tracing-diagnostic) and is a diagnostic tool that captures trace info and extends the WinDbg tool to load such trace files for further analysis. Tttracer allows you to select a specific process (or more) on your computer and collects info about it. At a later time, MS support is able to use such trace files and go back and forth in time to diagnose SharePoint processes before, during, and after issues.

Unfortunately, tttracer is not available outside Microsoft so of no immediate use to us. However, there were some steps in the trace capturing process that are good practices to follow anyway, such as:

1. If you’re interested in doing a memory dump, isolate a WFE that will be used for testing the issue.

2. If you’re interested in doing a memory dump, edit the host file on that WFE to ensure all SharePoint URL calls are directed to the WFE, and not to a load balancer.

3. Set ULS logging to verbose and put that info in a separate log file (via Set-SPLogLevel -TraceSeverity VerboseEx -EventSeverty Verbose and New-SPLogFile).

4. Reset IIS.

5. Reproduce the issue.

6. If you’re interested in doing a memory dump, find the process id of the application pool that hosts the SharePoint site where the issue occurs (by executing “%windir%\system32\inetsrv\appcmd list wps” on a command prompt).

8. Reproduce the issue.

9. Analyze all the info you retrieved.

We suspect your own troubleshooting may not be that different, and most likely will be more extensive than this, but for sure it won’t hurt to compare notes!

Profiling SharePoint databases

Of course messing with SharePoint databases is not supported but we’ve found there are times when we do want to take a closer look at SharePoint databases and see where certain information is stored or how long an operation takes at the database level. As we don’t do this that often, we thought it would be convenient to document the procedure for profiling SharePoint databases and also thought the write-up could be helpful for others.

Follow this procedure to start profiling databases:

1. Start SQL Server Profiler directly or via SQL Server Management Studio and then choose Tools > SQL Server Profiler.

2. Click File > New Trace. This opens the Connect to Server dialog window.

3. Enter the server name of the SharePoint database server or instance that you want to profile.

4. Click Connect.

5. This opens the Trace Properties dialog window.

6. Enter a valid Trace name.

7. In the Use the template drop down list, choose TSQL_Duration. This template is especially good for finding how long it takes to run SQL queries and stored procedures.

8. Click the Events Selection tab.

9. Select the Show all columns checkbox.

10. Check the DatabaseName column for both Stored Procedures and TSQL.

11. If you don’t know the exact name of the database(s) you want to profile, click Run.

Perform the UI actions that you want to investigate further, and click the Pause Selected Trace button. This gives you the chance to identify the names of the databases you’re interested in. Now that you’ve established that, you’re ready add a filter to profile only the databases you’re interested in and no more. This is a necessary step as the number of queries that are executed on a SharePoint database server are quite overwhelming. Typically, but not always, you’ll be most interested in the SP_Content_* databases.

Now follow the next procedure to add some filters:

1. Click the Clear Trace Window button.

2. Click File > Properties.

3. Click the Events Selection tab.

4. Click Column Filters. This opens the Edit Filter dialog window.

5. Select DatabaseName.

6. Click Like.

7. Enter the desired database name, e.g. %Content%.

8. Click Run.

Now you have a better chance to find out what’s taking so long and where specific information is stored.

Coding for kids

Margriet wrote an interesting blog post about getting kids in contact with programming. You can read more about it over here. In the Netherlands, there’s the option to join codeuur, in English, the article discusses a lot more options.

Browser chart site

Everybody needs a browser charting site to look up if a certain CSS, JavaScript or HTML 5 feature is supported or not, because it will save tons of time. We kinda like this one: http://caniuse.com/ It allows you to check if a feature is supported in a heartbeat, it allows you to compare multiple browsers and versions with each other, and it shows insights into usage info for your country!

Quick link title strangeness in SharePoint 2013: wrong Title value

There is some strangeness surrounding the retrieval of quick launch links in SharePoint 2013 which may very well be a bug in SharePoint. Although we’re the first ones to admit we haven’t been let in on the exact reasoning behind SharePoint’s implementation of the quick launch title, and there may be very good reasoning behind it, we’re inclined to believe that this is another area where multi-language scenarios have been implemented sloppily in SharePoint 2013. In this article we discuss what the problem is and, better yet, how to solve it.

In principle, retrieving the link title of a quick link is easy. The next C# code uses the server-side OM to retrieve the title of every first link of every web site in a site collection.

string siteUrl = “[site collection URL]”;
using (var site = new SPSite(siteUrl))
{
    foreach (SPWeb web in site.AllWebs)
    {
        string title = web.Navigation.QuickLaunch[0].Title;
    }
}

There are situations when the Title does not contain the value you’d expect. There are 2 preconditions that need to be met to experience this strangeness (there may be more scenarios causing it, but we’re describing the one we’ve encountered):

  • We’re editing the default first link of a new team site.
  • The locale of the thread running the code is different from the default language of the SharePoint web site.

To clarify, let’s present an example that runs as expected, then followed by the example that does not behave as we expect.

Example 1: Expected Title

  1. Create a new team site and choose language “English”.
  2. Go to the Navigation link (so the Publishing features need to be enabled in order to do this) and edit the first link and change it’s title to “Test”. Do not change the URL!
  3. Run the code and verify that web.Navigation.QuickLaunch[0].Title indeed returns the value of “Test”, the same value as seen via the UI in the quick launch bar.

Example 2: Unexpected Title

  1. Create a new team site and choose language “Dutch” (or some other language as long as its not English).
  2. Go to the Navigation link (so the Publishing features need to be enabled in order to do this) and edit the first link and change it’s title to “Test”. Do not change the URL as this will ensure the Title functionality to function correctly!
  3. Run the code and verify that web.Navigation.QuickLaunch[0].Title does not return the value of “Test”, but instead returns “Home”, even when the quick launch bar itself displays the link title “Test” correctly.

Inspecting the implementation of the Title property in the Microsoft.SharePoint.Navigation.SPNavigationNode class sheds some light on this issue:

public string Title
{
    get
    {
        if (System.Globalization.CultureInfo.CurrentUICulture.LCID == this.Navigation.Web.UICulture.LCID)
        {
            return this.m_strTitle;
        }
        return this.TitleResource.Value;
    }
}

In our case our code was running under a thread with the LCID of 1033 (English – United States). As long as the default language of the SharePoint web site is set to English, this works fine and the member variable m_strTitle is returned containing the correct quick link title value of “Title”.

But, when the LCID of our thread is 1033 and the default language of the SharePoint web site is set to Dutch, we get this.TitleResource.Value which is “Home” and that is incorrect.

As a remedy, we can use reflection to retrieve the value of private member m_strTitle. In C#, this goes like this:

SPNavigationNode firstLink = web.Navigation.QuickLaunch[0];
FieldInfo fieldInfo = firstLink.GetType().GetField(“m_strTitle”, System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
string realLinkTitle = fieldInfo.GetValue(firstLink).ToString();

In PowerShell, the same feat goes like this:

$site = Get-SPSite $siteUrl
foreach ($web in $site.AllWebs)
{
    $firstLink = $web.Navigation.QuickLaunch[0]
    $fieldInfo = $firstLink.GetType().GetField(“m_strTitle”,
        [Reflection.BindingFlags]::NonPublic
        -bor [Reflection.BindingFlags]::Instance)
    $actualLinkTitle = [string]$fieldInfo.GetValue($firstLink)

    $web.Dispose()
}
$site.Dispose()

Now, regardless of the thread your code is running in, you get the actual link title instead of the resource value.

SharePoint WPSC is undefined

In a SharePoint 2013 environment we encountered the error “WPSC is undefined”. The WPSC (Web Part Page Services Component) is a JavaScript library that web parts use to communicate with each other client-side. We don’t feel the WPSC used that often nowadays (if that ever was the case), so maybe that explains why we couldn’t find that much info about this problem. The most interesting post was this one: http://sadomovalex.blogspot.nl/2010/02/fix-wpsc-is-undefined-javascript-error.html

But it talks about an issue in combination with FBA, and our problem existed on a page leveraging WPSC for client-side communication when using MSIE 10 or higher (whereas MSIE 9 worked fine). Also, in normal mode the error existed in MSIE 10 and up, in page edit mode it went away. There’s another post worth mentioning, and its this one: http://msharaky.blogspot.nl/2009/06/wpsc-undefined-javascript-error.html

Here, the author defines a dummy object and reports the error goes away. This is true of course, but also kills client-side communication. But, if you’re just looking for a way to suppress an ugly error message, this one does the trick.

To understand more about the problem, it’s worth mentioning that the WPSC object is defined in a JavaScript library called ie55up.js which is included by default. So, if you’ve changed your master pages and its not referenced anymore, then there’s the place where it needs to be corrected.

Another useful thing to know is that if you’re using the SharePoint ScriptLink control to include a JavaScript library into your page, the OnDemand attribute determines if such a library will be included on demand as needed, or immediately. The following line ensures a JS library is loaded on demand:

<SharePoint:ScriptLink ID=”scriptLink1″ runat=”server” Name=”MyScriptLib.js” LoadAfterUI=”true” OnDemand=”true” />

If the js library needs to be loaded immediately, the control just generates a script tag. If the js library needs to be loaded on demand, it generates calls to the SharePoint RegisterSOD() JavaScript function. This is interesting because a SharePoint page in edit mode loads the ie55up.js immediately (and thereby the WPSC), using the following client-side code:

<script type=”text/javascript” src=”/_layouts/15/ie55up.debug.js?rev=pVBnO13dp7gFq%2FZalDmroA%3D%3D”></script>

Remember that the page in edit mode works correctly in conjunction with WPSC.

Note: the script tag refers to a debug version of ie55up.js instead of the minified version. That is because we have configured SharePoint to do this by setting the debug attribute in the web.config file to true.

On the other hand, a page in normal mode that uses the WPSC but fails in MSIE 10 and up renders the ie55up.js library to be loaded on demand, like so:

<script type=”text/javascript”>RegisterSod(“browserScript”, “\u002f_layouts\u002f15\u002fie55up.debug.js?rev=pVBnO13dp7gFq\u00252FZalDmroA\u00253D\u00253D”);RegisterSodDep(“browserScript”, “strings.js”);</script>

Apparently there is some on demand script problem because in which case the ie55up library is registered successfully, but never gets loaded in MSIE 10 and up. Btw, the root cause of this we have yet to discover.

Another thing to note is that the RegisterSod() function is defined in init.js and looks like this:

function RegisterSod(key, url) {
    ULSxSy: ;
    key = NormalizeSodKey(key);
    var sod = new Sod(url);
    _v_dictSod[key] = sod;
}

Later on, we’ll be able to leverage the facts that all keys are stored in the _v_dictSod dictionary and ie55up.js gets registered using the “browserScript” key to our advantage.

In order to experiment with this problem, we needed an easy way to add JavaScript code to a SharePoint page that uses the WPSC. We decided to place a Script Editor web part on a page (page edit mode > ribbon > Insert > Embed Code) that uses JavaScript that uses WPSC to register for a predefined event that happens when a user presses F1 to get help. All that’s needed to determine when and if the WPSC problem is an issue for you is this code:

<script>
WPSC.RegisterForEvent(“urn:schemas-microsoft-com:dhtml”, “onhelp”, myfunc); // respond to predefined event for pressing F1
</script>

Now our approach for dealing with the “WPSC is undefined” problem has 2 sides. If the WPSC object exists (in older browsers and page edit mode for msie 10 and up) we need to do the following:
1 – Establish that the WPSC exists.
2 – Do required communication via WPSC. In this case, we’ll use the WPSC to respond to an F1 key press.

In situations where the WPSC doesn’t exist, our approach is like this:
1 – Establish that the WPSC object does NOT exist.
2 – Find the URL that SharePoint intends to use to load ie55up.js.
3 – Use the SP.SOD library to load ie55up.js on demand.
4 – Establish that ie55up.js is indeed loaded.
5 – Do client-side communication via WPSC. In this case, we’ll use the WPSC to respond to an F1 key press.

This results in code that can be used as a work-around for situations where the WPSC is undefined, making sure its loaded on demand and then do the things you want to do with a fully functioning WPSC. You can paste the following code in a Script Editor web part on a SharePoint page to see it in action (after pressing F1):

<script>
function myfunc()
{
  alert(‘Responding to help!!!’);
}

function WpscLoaded()
{
  execWpscCalls();
}

function execWpscCalls()
{
  WPSC.RegisterForEvent(“urn:schemas-microsoft-com:dhtml”, “onhelp”, myfunc); // respond to predefined event for pressing F1
}

if (typeof(WPSC) == “undefined” )
{
  // default src of js lib defining WPSC
  var url = “\u002f_layouts\u002f15\u002fie55up.js”;

  // get url that sharepoint stores to refer to WPSC lib
  if (_v_dictSod != null && _v_dictSod[“browserScript”] != null)
  {
    url = _v_dictSod[“browserScript”].url;
  }
  SP.SOD.registerSod(‘ie55up.js’, url);
  SP.SOD.executeFunc(‘ie55up.js’, null, function(){});

  // when done, WPSC is available 
  ExecuteOrDelayUntilScriptLoaded(WpscLoaded, “ie55up.js”);
}
else
{
  execWpscCalls();
}
</script>

Are Draft versions of items and documents indexed in SharePoint 2013?

This can be tested for both lists and document libraries, and the answer depends on various list settings (a term we use in a generic way that also includes document library settings). Possible list settings are:
– Content approval setting: With or without content approval
– Draft item security: Any user who can read items, Only users who can approve items, or Any user who can approve items (and the author of the item).

Searching using the credentials of the author results in items in lists as well as document libraries that only require Read permissions (option “Any user who can read items”). All other Draft versions in lists and libraries with different settings are not included in search results. For instance, a document in Draft version in a library that has the following condition: [go to document library > Library > Library Settings > Versioning settings > Draft Item Security > Only users who can edit items] is NOT returned.

Searching under the context of a user that only has READ permissions yields the exact same search results.

Investigating the crawl log shows that the items that are not returned aren’t even indexed.