Showing posts with label PnP.Framework. Show all posts
Showing posts with label PnP.Framework. Show all posts

Thursday, August 19, 2021

Method not found error in UnifiedGroupsUtility.ListUnifiedGroups() when use PnP.Framework 1.6.0 with newer version of Microsoft.Graph

Today I've faced with interesting problem: in our .Net Framework 4.7.2 project we use PnP.Framework 1.6.0 (latest stable release currently) which was built with Microsoft.Graph 3.33.0. Then I updated Microsoft.Graph to the latest 4.3.0 version and after that UnifiedGroupsUtility.ListUnifiedGroups() method from PnP.Framework started to throw the following error:

Method not found: 'System.Threading.Tasks.Task`1<Microsoft.Graph.IGraphServiceGroupsCollectionPage> Microsoft.Graph.IGraphServiceGroupsCollectionRequest.GetAsync()'.

When I analyzed the error I found the following: Microsoft.Graph 3.33.0 contains IGraphServiceGroupsCollectionPage interface which has the following method:

In Microsoft.Graph 4.3.0 signature of this method has been changed: cancellationToken became optional parameter:

As result we got Method not found error in runtime. Interesting that app.config had binding redirect for Microsoft.Graph assembly but it didn't help in this case:

<dependentAssembly>
  <assemblyIdentity name="Microsoft.Graph" publicKeyToken="31bf3856ad364e35" culture="neutral" />
  <bindingRedirect oldVersion="0.0.0.0-4.3.0.0" newVersion="4.3.0.0" />
</dependentAssembly>

Also interesting that the same code works properly in project which targets .NET Core 3.1.

For .Net Framework project workaround was to copy code of UnifiedGroupsUtility.ListUnifiedGroups() from PnP.Framework to our project (fortunately it is open source) and then call this copied version instead of version from PnP.Framework. When new version of PnP.Framework will be released which will use newer version of Microsoft.Graph we may revert this change back.

Monday, July 19, 2021

How to edit properties of SPFx web part using PnP.Framework

In my previous post I showed how to add SPFx web part on modern page using PnP.Framework (see How to add SPFx web part on modern page using PnP.Framework). In this post I will continue to familiarize readers of my blog with this topic and will show how to edit web part properties of SPFx web part using PnP.Framework.

For editing web part property we need to know 3 things:

  • web part id
  • property name
  • property value

You may get web part id and property name from manifest of your web part. Having these values you may set SPFx web part property using the following code:

var ctx = ...;
var page = ctx.Web.LoadClientSidePage(pageName);

IPageWebPart webpart = null;
foreach (var control in page.Controls)
{
    if (control is IPageWebPart && (control as IPageWebPart).WebPartId == webPartId)
    {
        webpart = control as IPageWebPart;
        break;
    }
}

if (webpart != null)
{
    var propertiesObj = JsonConvert.DeserializeObject<JObject>(webpart.PropertiesJson);
    propertiesObj[propertyName] = propertyValue;
    webpart.PropertiesJson = propertiesObj.ToString();
    page.Save();
    page.Publish();
}

At first we get instance of modern page. Then find needed SPFx web part on the page using web part id. For found web part we deserialize its PropertiesJson property to JObject and set its property to passed value. After that we serialized it back to string and store to webPart.PropertiesJson property. Finally we save and publish parent page. After that our SPFx web part will have new property set.

Wednesday, July 14, 2021

How to add SPFx web part on modern page using PnP.Framework

If you migrated from OfficeDevPnP (SharePointPnPCoreOnline nuget package) to PnP.Framework you will need to rewrite code which adds SPFx web parts on modern pages. Old code which used OfficeDevPnP looked like that:

var page = ctx.Web.LoadClientSidePage(pageName);

var groupInfoComponent = new ClientSideComponent();
groupInfoComponent.Id = webPartId;

groupInfoComponent.Manifest = webPartManifest;
page.AddSection(CanvasSectionTemplate.OneColumn, 1);

var groupInfiWP  = new ClientSideWebPart(groupInfoComponent);
page.AddControl(groupInfiWP, page.Sections[page.Sections.Count - 1].Columns[0]);

page.Save();
page.Publish();

But it won't compile with PnP.Framework because ClientSideWebPart became IPageWebPart. Also ClientSideComponent means something different and doesn't have the same properties. In order to add SPFx web part to the modern page with PnP.Framework the following code can be used:

var page = ctx.Web.LoadClientSidePage(pageName);

var groupInfoComponent = page.AvailablePageComponents().FirstOrDefault(c => string.Compare(c.Id, webPartId, true) == 0);
var groupInfoWP = page.NewWebPart(groupInfoComponent);
page.AddSection(CanvasSectionTemplate.OneColumn, 1);
page.AddControl(groupInfoWP, page.Sections[page.Sections.Count - 1].Columns[0]);

page.Save();
page.Publish();

Here we first get web part reference from page.AvailablePageComponents() and then create new web part using page.NewWebPart() method call. After that we add web part on a page using page.AddControl() as before. Hope it will help someone.

Monday, July 12, 2021

Use assemblies aliases when perform migration from SharePointPnPCoreOnline to PnP.Framework

Some time ago PnP team announced that SharePointPnPCoreOnline nuget package became retired and we should use PnP.Framework now. Latest available version of SharePointPnPCoreOnline is 3.28.2012 and it won't be developed further. Based on that recommendation we performed migration from SharePointPnPCoreOnline to PnP.Framework. During migration there were several interesting issues and I'm going to write series of posts about these issues.

One of the issue was that one class SharePointPnP.IdentityModel.Extensions.S2S.Protocols.OAuth2.OAuth2AccessTokenResponse was defined in 2 different assemblies in the same namespace:

  • SharePointPnP.IdentityModel.Extensions.dll
  • PnP.Framework

Compiler couldn't resolve this ambiguity and showed an error:

Since class name is the same and namespace is the same - in order to resolve this issue we need to use  quite rarely used technique called extern aliases. At first in VS on referenced assembly's properties window we need to specify assembly alias. By default all referenced assemblies have "global" alias - so we need to change it on custom one:


Then in cs file which has ambiguous class name on the top of the file we need to define our alias and then add "using" with this alias:

SharePointPnPIdentityModelExtensions;
...
using SharePointPnPIdentityModelExtensions::SharePointPnP.IdentityModel.Extensions.S2S.Tokens;

After these steps compilation error has gone and solution has been successfully built.