Sharepoint - How to Provision a list with data using SharePoint Online PnP C#?

I have done a similar thing recently and have written an article about it. You can easily achieve this by running some SharePoint PowerShell commands.

Connect-SPOService -Url https://yoursharepoint-admin.sharepoint.com

Set-SPOsite https://yoursharepinttenant.sharepoint.com/sites/yoursharepointsite -DenyAddAndCustomizePages 0

Connect-PnPOnline https://youradmin.sharepoint.com/sites/yoursite/

Get-PnPProvisioningTemplate -Out c:/Provisioning/template.xml

Add-PnPDataRowsToProvisioningTemplate -Path c:/Provisioning/template.xml -List 'The list name' -Query '<view></view>'

Connect-PnPOnline https://youradmin.sharepoint.com/sites/yourdetinationsite

Apply-PnPProvisioningTemplate -Path C:/Provisioning/template.xml

Hope it helps.


This is by design. PnP will only migrate the structure and content types and not data.

To provision the data, you will need to write a custom extensibility provider. You need to write that in your provisioning template xml somewhat as below:

<pnp:Providers>
  <pnp:Provider Enabled="true" HandlerType="PnP.ExtensibilityProviders.CustomProvider, PnP.ExtensibilityProviders, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null">
    <pnp:Configuration>
      <CustomProviderConfiguration id="SampleConfig" xmlns="http://schemas.somecompany.com/MyProviderConfiguration">
        <ChildNode Attribute="value">Some Content</ChildNode>
        //write your custom xml tree structure
      </CustomProviderConfiguration>
    </pnp:Configuration>
  </pnp:Provider>
</pnp:Providers>

The extensibility provider is nothing but a class implementing the IProvisioningExtensibilityProvider interface as below:

namespace PnP.ExtensibilityProviders 
{
  public class CustomProvider : IProvisioningExtensibilityProvider
  {
    public void ProcessRequest(ClientContext ctx, ProvisioningTemplate template, string configurationData)
    {
        // do something in your provider       

        //something as follows
        List oList = ctx.Web.Lists.GetByTitle("Announcements");
        ListItemCreationInformation itemCreateInfo = new ListItemCreationInformation();
        ListItem oListItem = oList.AddItem(itemCreateInfo);
        oListItem["Title"] = "My New Item!";
        oListItem["Body"] = "Hello World!";
        oListItem.Update();
        ctx.ExecuteQuery(); 

        // or something as below 

        var customData = GetValueFromXMLString(configurationData);
        //read and parse the string and then provision data     

    }
  }
}

Here, now you have 2 choices:

1) Define your custom XML structure in the provisioning xml, then read and parse that in your provider. This will be helpful if you need to reuse the data and you keep similar structure across some lists. This will reduce your lines of code.

2) Just keep the extensibility provider xml to barest minimum(as above) and handle everything in the class. This will increase the lines of code if you have too many extensions. But if its just a couple of records, would suggest that you use this one.

References - Provisioning.Extensibility

Custom Extensibility Handlers for PnP Provisioning Framework


i managed to do this by adding rows as XML, a alternative option for some scenarios, perhaps?enter image description here

<pnp:Lists>
   <pnp:ListInstance Title="bookings" Description="bookings list demo" TemplateType="100" Url="Lists/bookings" >
      <pnp:DataRows UpdateBehavior="Overwrite">
         <pnp:DataRow>
            <pnp:DataValue FieldName="Title">Taming of the Shrew</pnp:DataValue>
            <pnp:DataValue FieldName="dateFrom">10/10/2018</pnp:DataValue>
            <pnp:DataValue FieldName="dateTo">Sample Project 01</pnp:DataValue>
            <pnp:DataValue FieldName="noOfTickets">4</pnp:DataValue>              
         </pnp:DataRow>
         <pnp:DataRow>
            <pnp:DataValue FieldName="Title">Hamleta</pnp:DataValue>
            <pnp:DataValue FieldName="dateFrom">11/11/2018</pnp:DataValue>
            <pnp:DataValue FieldName="dateTo">Sample Project 02</pnp:DataValue>
            <pnp:DataValue FieldName="noOfTickets">5</pnp:DataValue>
         </pnp:DataRow>
         </pnp:DataRows>
        </pnp:ListInstance>