SharePoint Dragons

Nikander & Margriet on SharePoint

Tag Archives: sharepoint

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.

Advertisements

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.

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.

Another nice SharePoint 2013 Feature Overview

Yet another nice overview of SharePoint 2013 features at http://blog.blksthl.com/2013/01/14/sharepoint-2013-feature-comparison-chart-all-editions/#SIT . In case you need it! For a collection of quality feature overview pages check out http://social.technet.microsoft.com/wiki/contents/articles/12438.sharepoint-2013-best-practices.aspx#Feature_Overview

SharePoint Adoption Kit and Guideline

You might want to check out the Microsoft Adoption guideline at http://aka.ms/spadoptwp and Adoption Kit at

http://aka.ms/spkit

Let’s Discover SharePoint

MS has launched a nice site that is targeted to potential customers wanting to get to learn SharePoint at http://www.discoversharepoint.com/

SPCAF

SPCAF

SharePoint Code Analysis Framework (SPCAF) currently is a free beta tool (http://visualstudiogallery.msdn.microsoft.com/d3b2aaf7-0d6a-4995-a4e5-4153c57e3889) and remains that way until 2013/09/30, but eventually will become a commercial product. SPCAF currently uses +/- 300 rules dedicated to SharePoint analyzing compiled code, XML files, user controls (*.ascx files), pages (*.aspx files), and master pages (*.master files). It integrates in Visual Studio and is also available as a separate client application that can be run from the command line. The following Figure shows a screenshot of the client application.

Pic1

The following Figure shows a dependency graph that understands SharePoint solution files.

pic2

SPCAF rules are divided in various categories:

· Correctness. Correctness rules check the SharePoint XML code for syntax errors. This includes check for all required XML attributes, correct values and data types of attributes. For example, such rules check for required Id attributes in the <Solution> element, valid GUIDs, and checks Feature folder and file names don’t contain spaces.

· Security. Checks if solutions pose security issues. For example, such rules check for calls to SPWeb.AllowUnsafeUpdates, WindowsIdentity.Impersonate() calls, running with elevated privileges, specific CAS policy settings, and presence of a form digest control in *.aspx pages.

· SharePoint Supportability. Checks if solutions endanger the supportability of SharePoint. For example, such rules check for attempts to change system files, accessing the SharePoint API via reflection, reading the content database connection string, and querying SharePoint databases directly.

· Design. Warnings that support proper library design. For example, such rules check for presence of assembly file version number, hard coded URLs, and programmatically created content types.

· Best Practices. Rules to warn if best practices are not used. For example, such rules check for direct calls to Item collection of SPList, check if locking is used when storing objects in SharePoint cache, and instantiating new list, list object, sites, and/or webs in event receivers.

· Deployment. The deployment process of SharePoint customizations is often a critical part. Deploying the wrong way or the wrong files can harm the SharePoint farm or make the farm inaccessible. Deployment rules check the code for these risks or potential problems. For example, such rules check for global deployments, web server resets in code during deployment, deploy assemblies in Debug mode, and deployment of web services to the SharePoint LAYOUTS folder.

· Localization. Localization is the process of customizing an application, webpage, or website for a given culture or locale. The localization rules check if all attributes in XML which support localization are localized in a proper way. For example, such rules check that localizable attributes (such as display names) use resources and more.

· Naming. Checks files and artifacts for violations against naming conventions. For example, such rules check for valid namespaces, names of web templates that start with &apos;WEBTEMP&apos;.

· Customization. Rules which check violations against SharePoint customization guidelines. For example, such rules check for the presence of HTTP handlers and/or modules, presence of timer jobs, presence of event receivers, and presence of inline code in .aspx pages.

· Sandboxed compatibility. Checks files and artefacts whether they are compatibel with Sandboxed solutions requirements. For example, such rules check for presence of APTCA attribute, references to .NET assemblies that are unavailable within the sandbox, and HideCustomAction elements.

· SharePoint 2007 compatibility. Checks files and artefacts whether they are compatibel with SharePoint 2007. For example, such rules check for references to the correct assemblies.

· SharePoint 2010 compatibility. Checks files and artefacts whether they are compatibel with SharePoint 2010. For example, such rules check for check for references to the correct assemblies, and deprecated API calls.

· SharePoint 2013 compatibility. Checks files and artefacts whether they are compatibel with SharePoint 2013. For example, such rules check for references to the correct assemblies, .NET 4.5 target framework, and deprecated API calls.

SPCAF promises to become the most powerful tool when it comes to analyzing custom SharePoint solutions, but we’ll keep our eyes on the tool!

Discount for IT/Dev Connection Friends

There are many shades of friends, but by reading this blog, I (Margriet) consider you to be a SharePoint technology friend! After checking with my MS MVP contact, I found out I’d be allowed to share a discount code with you for the IT/Dev Connections that is held on September 30 – October 4 in Mandalay Bay, Las Vegas (http://www.devconnections.com/dev13/public/mainhall.aspx). This offer gives you a $100 discount on the registration fee.

What to do?

Just drop me an e-mail (margriet at loisandclark dot eu) and I will send you a promo code in return. During the registration, when prompted for a promo code, you will need to enter that promo code. You will be asked “How did you hear about the IT/Dev Connections?”. You will need to select. “friend/colleague” and then enter “MVP: Margriet Bruggeman” when prompted.