Before starting, we need to remember a couple of things regarding the PnP program. First of all, the August release has been made recently, which includes numerous upgrades in the Provisioning part, and a new XML Schema. You have all the details in the link https://dev.office.com/blogs/PnP-August-2016-Release.
Some of the most outstanding changes are:
- Support for setting up the Navigation, both Structural and by Metadata
- Support for breaking the inheritance of roles in Subsites
- Support for User Custom Actions at list level
- Support for reused and deprecated Terms
- Delete Custom Action (until now, you could only add new CustomActions)
As well as the architecture diagram of the provisioning process, where in the point 5 of the image, we can see that the ExtensibilityHandlers that have been set up in the template are executed:
Finally, before entering into the code, we need to highlight that the Extensibility Handlers can be executed both in the Provisioning and Export process, (initially, the Extensibility Handlers were called Provisioning Extensibility Providers, and they were only executed in the provisioning process, therefore it was not possible to execute custom mode when exporting a site as a template).
Creating our custom Extensibility Handler
In the article’s example, we are going to create a custom Extensibility Handler, that will be used to trace the different templates applied to a site. For this, we will create first a simple PnP template in XML, which will provision a custom list, that will be used as Log “table”. Next, we will create our custom Extensibility Provider, that in each provisioning action, will insert a new item in the Log list, including certain information of the template. Finally, we will see how to register our Extensibility Provider inside the PnP template itself, and we will execute the provisioning to watch it working.
To create our Extensibility Handler, we just need to create a new class library, and that our class implements the interface IProvisioningExtensibilityHandler defined inside the PnP Core. After doing this and install the interface, we will have the following code:
The first Extract method will be executed when the Export is made of an existing site to a PnP template. In our example, we are going to focus in the provisioning action, and we are not going to do anything when exporting the site, so we will just return the same template that the method receives:
The method GetTokens will allow us to expand the collection of Tokens that will receive later the Provision action. The PnP Provisioning framework uses the class TokenParser, that allow us to use tokens in the definition of the template. Those tokens are resolved in execution time, and replaced by the true value, depending on the context. For instance, we can use the token ~sitecollectiontermstoreid that will be replaced by the ID of the TermStore of the tenant, and that is very useful for provisioning Site columns of managed metadata. The Framework has a lot of tokens and probably it will cover everything we need, but if not, we can use this method to expand the list of Tokens.
For the example, we are going to create a Token, that will be replaced by the value of a PropertyBag of the web. For that, we create a new class, derived from TokenDefinition
Finally, we overwrite the method GetRePlaceValue() where the replacement of the token is made by the true value. In this code, we make use of a new Extension of the PnP itself, which makes easier to obtain a PropertyBag.
Once the token is defined, it is time to go back to the Extensibility Handler, and user it:
The last step is to complete the Provision method, where we insert the new item in the Log list.
But before that, we are going to see how to register our custom Handler in the PnP template. For that, we will use the Provider node, available inside the PnP schema, and we point it to our new class custom Handler:
Until the Configuration mode, everything follows the PnP schema. Inside that node, we can add all the XML that we need, the only requirement is that in the root node, we define a NameSpace (xmins), which we will use from the code to load the XDocument. In the example, we simplified it to the maximum, and we are only using the Token previously defined, to check that everything works correctly. We will insert that value in the item of the Log list.
Bug in the PnP-Sites-Core dll
If you put a breakpoint in the method GetTokens, you will notice that method is not being never executed. I think there is a bug in the .dll of the PnP Core. I am going to try to do a Pull Request to the GitHub project to fix the bug to have it ready for the next release on September, but if not, here you have how to resolve it, that obviously implies to change the code in the .dll of the PnP, so, if you have to do it, you will not be able to use the Nuget package.
To fix this, firstly we have to edit the file ExtensibilityManager.cs and change the method header:
We will also need to edit the file ObjectExtensibilityHandlers.cs and modify the method AddExtendedTokens changing the line 28:
With both changes we will fix the bug, and our Extensibility Provider will work as expected.
Going back to the Provision method of our custom Handler, we will have the following code to create a new item in the Log list.
As I say in the comment, the entry parameter configurationDate contains the custom XML that we previously defined in the PnP template. Besides, this string comes with all the tokens solved by the TokenParser, including the custom tokens that we have added in the implementation of GetTokens.
Once we have created our Handler, we can apply a PnP template, and see the result. The PnP template used is as follows:
In that template a property bag is provisioned with the value of the version of the template that we are applying. In addition, the Log list is provisioned with a couple of fields and finally, our custom Handler is registered.
With the following code, we can apply the template from the XML file and provision it to a SharePoint online site:
Once we had applied the template, we can view our Log list, with an element with the version of the template.
If now we apply again the template, but we change the value of the property bag, we have a second element in the list, with the identifier that we have given to the template:
That's all, now that we know how to create our own Extensibility Handlers, and that these serve for both the extraction of template, and for applying it to a new site, there is no excuse for not using PnP Provisioning Framework, given that any specific need that the frameworks does not cover can be developed with custom CSOM.