[ X ] Bug
[ ] Enhancement
[ X ] Office 365 / SharePoint Online
[ ] SharePoint 2016
[ ] SharePoint 2013
I have written an Extensibility Handler for PnP Engine, and I expect that the override of Provision method always receives a _ClientContext_ set on the _Web_ object for which the provisioning template is being applied on, otherwise isn't easy to retrieve an instance to this object.
When the _ClientContext_ is set to the _Web_ to which the template is being applied on, everything works as expected. When it's set to a different object (e.g. the parent site), then my override just receives the _ClientContext_ object, and no reference to the _Web_ object where the template is being applied.
This is an issue for instance in PnP Partner Pack, which has some mechanism similar as sample below
For instance, we instantiate the _ClientContext_ to the container site collection URL, create a new OOB Team Site child, and try to apply a provisioning XML template that references a custom Extensibility Provider.
```c#
static void Main(string[] args)
{
//init variables
//..
var siteCollectionUrl = "https://contoso.sharepoint.com";
using (var context = new PnPClientContext(siteCollectionUrl))
{
context.Credentials = new SharePointOnlineCredentials(tenantAdminUser, spwd);
var web = context.Web.CreateWeb("TeamTest", "teamtest", string.Empty, "STS#1", 1033, false, true);
context.Load(web);
context.ExecuteQueryRetry();
var info = new ProvisioningTemplateApplyingInformation();
info.HandlersToProcess = Handlers.ExtensibilityProviders;
web.ApplyProvisioningTemplate(template, info);
}
}
```
So, in example above, we have
Context / Site Collection URL: https://contoso.sharepoint.com
Web URL (where template is applied): https://contoso.sharepoint.com/teamtest
My override of Provision receives a _ClientContext_ set to the root web, and no reference to that one where the template is applied
I've found a workaround I can share if needed (to implement in the schema), but that doesn't fix the cause
I think this is quite serious, quite surprised it hasn't been discovered of covered by unit tests yet.
Do you think is it an easy fix? Something I can help on?
Haven't tried debugging it yet, but I'll post update in case I found a fix
Hi biste5,
I have a solution for how to get the web context of the newly created web inside the IProvisioningExtensibilityHandler You can use the provisioning engine tokens specified here to pass configuration data to your handler.
So inside your template you can use a token like so:
<pnp:Providers>
<pnp:Provider>
<pnp:Configuration>
<Config xmlns="http://schemas.com/emailextensibilityprovider">
<newSiteUrl>{site}</newSiteUrl>
</Config>
</pnp:Configuration>
</pnp:Provider>
</pnp:Providers>
You can then access this site value inside your provision function which will be populated with the newly created web URL.
XNamespace ns = "http://schemas.com/emailextensibilityprovider";
XDocument doc = XDocument.Parse(configurationData);
var newWebUrl = doc.Root.Descendants(ns + "newSiteUrl").FirstOrDefault().Value;
newWebUrl = ctx.Url + newWebUrl.Replace(ctx.Web.ServerRelativeUrl, "");
You could then new up a new ClientContent with the web URL.
ClientContext webClientContext = ctx.Clone(newWebUrl);
Correct, that's the workaround I implemented. Even if to be completely correct as you aren't sure if the template is applied from the web itself, or the parent, I also have this in my extensibility handler
```c#
web = ctx.Web;
ctx.Load(web, w => w.Url, w => w.ServerRelativeUrl);
ctx.ExecuteQueryRetry()
var siteInfo = new ExtensibilitySiteInfo();
if (!string.IsNullOrEmpty(configurationData))
{
XNamespace ns = "http://schemas.somecompany.com/MyProvisioningExtensibilityHandlerConfiguration";
var configXml = XDocument.Parse(configurationData);
siteInfo.SiteUrl = configXml.Root.Element(ns + "SiteInfo")?.Attribute("Url")?.Value;
}
if (!string.IsNullOrEmpty(siteInfo.SiteUrl) && !siteInfo.SiteUrl.Equals(web.ServerRelativeUrl, StringComparison.CurrentCultureIgnoreCase))
{
web = web.GetWeb(siteInfo.SiteUrl.Split('/').Last());
ctx.Load(web, w => w.Url, w => w.Title);
ctx.ExecuteQueryRetry();
}
```
so the field web will always have the correct reference to the web where template is being applied