Tag: SharePoint Online

An Outlook Add-in with SharePoint Framework (SPFx) – Retrieving the mail as Mime

An Outlook Add-in with SharePoint Framework (SPFx) – Retrieving the mail as Mime

Since SharePoint Framework version 1.10 you can also develop Office Add-Ins with SPFx starting with Outlook Web Access in public preview. The great benefit is you already have the prepared context for access of Microsoft Graph. In this demo scenario I want to show you how to create a valuable Outlook Add-In with the capability to store complete mails to OneDrive, Office 365 Groups or Microsoft Teams.

An Outlook Add-In to copy a whole mail to Teams, Groups or OneDrive

In this part you will see how to retrieve a mail as a whole mimestream so you can later store it as a file. In the past this was possible with the (meanwhile deprecated) Exchange asmx web-Services. Nowadays at there is also a Microsoft Graph endpoint for this.

The Api is simple me/messages/${mail.id}/$value
In the following function we are calling that endpoint and using the response to handover to next function for storing it somewhere.

GraphController: Retrieve Mail as MimeStream

Several parameters are not really needed here they are just handed in to handover to the next function for handling the response. The only needed parameter here is the mail respectively its id.

Once we have a positive result we need to check the size of the response, that is our mimestream. This is because for a file save operation via Microsoft Graph there are two different scenarios one simple scenario for files smaller than 4MB and a more complex one for files larger than 4MB. But this difference we will cover in the final part where we handle the storage operation of the the mimestream to a Group, Team, SharePoint or OneDrive. So stay tuned.

Meanwhile you can check the full code repository here in my GitHub.

Markus is a SharePoint architect and technical consultant with focus on latest technology stack in Office 365 and SharePoint Online development. He loves the new SharePoint Framework as well as some backend stuff around Azure Automation or Azure Functions and also has a passion for Microsoft Graph.
He works for Avanade and is based in Munich.
Although if partially inspired by his daily work opinions are always personal.
An Outlook Add-in with SharePoint Framework (SPFx) – Browsing your target OneDrive, Groups, Teams

An Outlook Add-in with SharePoint Framework (SPFx) – Browsing your target OneDrive, Groups, Teams

Since SharePoint Framework version 1.10 you can also develop Office Add-Ins with SPFx starting with Outlook Web Access in public preview. The great benefit is you already have the prepared context for access of Microsoft Graph. In this demo scenario I want to show you how to create a valuable Outlook Add-In with the capability to store complete mails to OneDrive, Office 365 Groups or Microsoft Teams.

An Outlook Add-In to copy a whole mail to Teams, Groups or OneDrive

In this part you will see how to retrieve all joined Groups or Teams and further retrieve the drives or folders, also from OneDrive, to browse them and select one as the target.

The UI simply follows quite the same process than moving an item within OneDrive or SharePoint. At first you can select your target system OneDrive, Office 365 Groups or Microsoft Teams.

Once you click one, and here we start with Groups respectively Teams as they are “higher” in terms of object hierarchy, we need to list all available Groups or Teams to the user . Therefore we have two functions in our GraphController.

GraphController: GetJoined Groups and Teams

As we do not need specific attributes of Groups and Teams, only as a parent container for browsing we treat them as a folder (IFolder interface). Drives and folders itself will only need the same attributes (id, name, optionally reference to parent item).

At the beginning of our “Groups” or “Teams” component we call that method and put the retrieved items as folders to our state.

We then render them in a simple way. This will be repeated later for all child items the same way.

Teams component (Groups component quite similar)
Folder component

Interesting is the subFolderCallback attribute of each folder which is set in the render function. In case we have a parent item (which has a parentFolder of null) we know this is a Group or Team. So once you click on it you want to see the drives below. In all other cases such as a drive or a folder a click on it wants to retrieve folders as child components. This is always the same method.

GraphController: GetDrives and SubFolders

As a folder has a parentFolder attribute of same type IFolder that parent also has/can have a parentFolder. With that information we can also create our simple breadcrumb.

Breadcrumb component

This breadcrumb can have up to three parts:

A << root anchor which brings you back to the root. The grandParenFolder (here “Folder 1”) which has a link and brings you one level up and a parentFolder (here “Subfolder 1”) which is not linked as it is the current location where you would store your mail right now in case you push the button and from which you might see eventually available child items.

In OneDrive it works quite the same but with two levels less as you only have one OneDrive (and not several Groups or Teams) and directly want to list the first level of folders once you open it. From there the functionality is quite the same.

In the next part we will get to know how to retrieve our mail as a full MimeStream object from Microsoft Graph.

Meanwhile you can check the full code repository here in my GitHub.

Markus is a SharePoint architect and technical consultant with focus on latest technology stack in Office 365 and SharePoint Online development. He loves the new SharePoint Framework as well as some backend stuff around Azure Automation or Azure Functions and also has a passion for Microsoft Graph.
He works for Avanade and is based in Munich.
Although if partially inspired by his daily work opinions are always personal.
An Outlook Add-in with SharePoint Framework (SPFx) – Introduction

An Outlook Add-in with SharePoint Framework (SPFx) – Introduction

Since SharePoint Framework version 1.10 you can also develop Office Add-Ins with SPFx starting with Outlook Web Access in public preview. The great benefit is you already have the prepared context for access of Microsoft Graph. In this demo scenario I want to show you how to create a valuable Outlook Add-In with the capability to store complete mails to OneDrive, Office 365 Groups or Microsoft Teams.

An Outlook Add-In to copy a whole mail to Teams, Groups or OneDrive

Let’s start the first part by creating our first Outlook Add-In. It’s already documented quite well in a Microsoft tutorial and I won’t repeat the necessary steps here and they are also quite familiar to you I suppose as you are not new to SharePoint Framework.

The only difference I made to the tutorial above and what you can do as well of course: Use the “React Framework” instead of “No JavaScript Framework”.

At first lets only take a short look into the Outlook Add-In manifest. I won’t go into details about changing position or logo or something but at least a custom title we should give. Therefore open the XML file in the \officeAddin folder and set the following settings according your choice:

What we need to do next is to get our current mail as we want to run our add in in the context of a selected mail. The following code snippet simply handles that:

Base Webpart render function

We first check this.context.sdks.office and if we have that we try to use this.context.sdks.office.context.mailbox.item. From there we can retrieve the mail ID and the subject which we will need at a later point of time. We hand them over to our first React component and in case we found nothing we will handle that null value adequately. On top we hand over the msGraphClientFactory which we will use to connect to Graph for folder retrieval, mail storage and so on.

That component I reduced a bit in code and explanation here. The main task is to render the initial logic for browsing your Teams, Groups or OneDrive folders but also hold the storage methods. Both I will cover in separate parts. The full code you can find in my GitHub repository.

Base Component

First we instantiate a GraphController and once ready it is set to the state so we know it’s there and can display our entry points for OneDrive, Groups and Teams accordingly.

In the second part we will get to know the browsing logic through all available Teams, Groups respectively OneDrive Folders where we can store our mail.

Meanwhile you can check the full code repository here in my GitHub.

Markus is a SharePoint architect and technical consultant with focus on latest technology stack in Office 365 and SharePoint Online development. He loves the new SharePoint Framework as well as some backend stuff around Azure Automation or Azure Functions and also has a passion for Microsoft Graph.
He works for Avanade and is based in Munich.
Although if partially inspired by his daily work opinions are always personal.
PnP SPFx React Carousel improvements – Dot Navigation

PnP SPFx React Carousel improvements – Dot Navigation

The PnP SPFx React Control carousel is great when it comes to display various content on limited amount of space. Recently I had to implement two improvements which I now want to share with you. While another idea would be to directly implement this into the control itself.

In this second part of the carousel improvements we want to implement a dot navigation, that is showing dots for each existing element inside the carousel control. It allows us to directly navigate to each of the elements and also shows us the current position of the active element (full vs empty circle).

For simplicity reasons we omit retrieving data and mapping to content elements but simply use pre-defined react elements as in the PnP SPFx React test webpart. I also assume you already know how to install PnP SPFx React controls.

Carousel – The basics

This is the same starting point as in part 1. We can skip the state here for the moment. But again we take a look at our pre-defined elements AND the case that the carousel uses our implemented triggerNextElement function. Also remember that the “key” attribute of the elements is mandatory in combination with TriggerNextPage.

Carousel – Dot Navigation

The first thing we note here, is the creation of the dot navigation (dotNav). We create Icon elements per each existing content element from above. The name of the Icon is either “StatusCircleRing” or in case we have the element with the current index “StatusCircleInner” which is the filled circel. Furthermore we style the Icon a bit (refer to my GitHub repository for further details) and we connect the onClick event with our triggerNextElement function.

This function is exactly the same is in part 1: It only updates the current state after it ensures the index always stays in the given range (0 to element length -1).

So although we skipped the state above: It’s essential to control the current index as well as the (dis)ability to move to prev/next element. Although there is an infinite property in the pnp carousel control it seems not to work when TriggerNextPage is implemented.

The final solution might look like this:

Carousel Dot Navigation – Final result

That’s all and nothing really complex right? Nevertheless feel free to inspect the whole solution in my public GitHub repository.

Markus is a SharePoint architect and technical consultant with focus on latest technology stack in Office 365 and SharePoint Online development. He loves the new SharePoint Framework as well as some backend stuff around Azure Automation or Azure Functions and also has a passion for Microsoft Graph.
He works for Avanade and is based in Munich.
Although if partially inspired by his daily work opinions are always personal.
PnP SPFx React Carousel improvements – Autoplay

PnP SPFx React Carousel improvements – Autoplay

The PnP SPFx React Control carousel is great when it comes to display various content on limited amount of space. Recently I had to implement two improvements which I now want to share with you. While another idea would be to directly implement this into the control itself.

In this first part of the carousel improvements we want to implement an autoplay, that is automatically moving forward through all content elements of the carousel control. For simplicity reasons we omit retrieving data and mapping to content elements but simply use pre-defined react elements as in the PnP SPFx React test webpart. I also assume you already know how to install PnP SPFx React controls.

Carousel – The basics

First we have 5 pre-defined content elements. As you would usually create them from retrieved data we also copy them to the current state where we also hold the currently displayed element and its index.

We then are going to render our carousel element with its defined properties. Pay attention that we only hand in ONE element here, the current one and that the carousel logic is driven by the triggerPageEvent method. Please also note that for working properly it’s essential that the elements hold a “key” property sor sorting purposes.

Now lets handle the autoplay logic:

Carousel – The autoplay logic

In the componentDidMount we start an interval. The delay is the given interval property in seconds but we have to multiply with 1000 to have the required milisceonds in this case. The interval starts another function, the autoplayElements. This function will be called in the given intervals (all X * 1000 miliseconds) and always load the next element (currentCarouselIndex + 1).

To load the element we have the triggerNextElement function. This one was already referenced above by our carousel control, that is because it is not only used by autoplay but also when you click the next or prev button. This function only updates the current state after it ensures the index always stays in the given range (0 to element length -1).

The final solution might look something like this:

Carousel Autoplay – Final result

That’s all and nothing really complex right? Nevertheless feel free to inspect the whole solution in my public GitHub repository.

Markus is a SharePoint architect and technical consultant with focus on latest technology stack in Office 365 and SharePoint Online development. He loves the new SharePoint Framework as well as some backend stuff around Azure Automation or Azure Functions and also has a passion for Microsoft Graph.
He works for Avanade and is based in Munich.
Although if partially inspired by his daily work opinions are always personal.

Deploy SPFx app package to SharePoint from Azure DevOps with modern authentication

As you can see from my last posts I got heavily involved in dealing with SharePoint modern authentication in the recent past. To repeat once again:

Intro

If your tenant has turned off legacy authentication you cannot simply authenticate with PowerShell and UserCredentials anymore. To check this run the following script:

Connect-SPOService -Url "https://<Your-Tenant>-admin.sharepoint.com"

$tenantsettings = Get-SPOTenant

$tenantsettings.LegacyAuthProtocolsEnabled

And potentially modify this setting (turn on: $true)

Set-SPOTenant -LegacyAuthProtocolsEnabled $true

In one of my last posts I showed how modern authentication is handled in a PowerShell script, especially in an Azure Automation environment where you can store and retrieve the necessary self-signed certificate as an Azure Automation asset.

Now another challenge: Inside an Azure DevOps Release pipeline you have another one or two PowerShell tasks. In my scenario two, one for uploading the app package to the app catalog, a second one to upload the assets to a SharePoint library, that is your Office 365 public CDN.

In Azure DevOps Release (and Build) pipelines you have no capability to simply store a certificate as an asset. Have it in the source code might not be an option to not distribute it to any developer’s environment. I only found the way to store variables (strings!), if anyone else has a better idea, speak up please 🙂

Fortunately this is also a working scenario as you can connect to SharePoint with another variant of the Connect-PnPOnline cmdlet providing a PEMCertificate and a PEMPrivateKey, both represented by large strings. According to my last post both can be simply extracted from a certificate once it is created by the New-PnPAzureCertificate cmdlet.

$Password = "******"
$secPassword = ConvertTo-SecureString -String $Password -AsPlainText -Force
$cert = New-PnPAzureCertificate -Out "AzureAutomationSPOAccess.pfx" - `
 -ValidYears 10 `
 -CertificatePassword $secPassword
 -CommonName "AzureAutomationSPOAccess" `
 -Country "DE" `
 -State "Bavaria"
$PEMCert = $cert.Certificate
$PEMSecret = $cert.PrivateKey 
Write-Host $PEMCert
Write-Host $PEMSecret

On top you also have to output the KeyCredentials and combine them with an Azure AD App registration.

Release pipeline basic configuration

In the past I mentioned Elio Struyf as a good resource for SPFx Azure DevOps Build&Release Pipelines but today I would also like to mention the blogpost of Giuliano de Luca which lists up all the necessary steps and options in a fantastic way.

In my simple scenario I picked most of the basics from him but I prefer to use a Release Pipeline only in staging environments (as you have to package for every stage again (changes in write-manifest.json for instance). But to simplify we will cover only one stage:

Simple Azure DevOps SPFx Release Pipeline (1 Stage)
Azure DevOps Release Pipeline – The Tasks

The first tasks are quite obvious. At first we follow a recommendation from Elio to use Node version 8 which significantly improves performance. Afterwards we run npm install, bundle and package our solution.

Here I want to give you a special hint on dealing with larger projects:

There I tend to use larger Git repositories, meaning not every SPFx solution has it’s own like the typical standard deployment demo scenario. That leads to the point where the standard file structure is not valid anymore. When entering the System.DefaultWorkingDirectory followed by your Artifact folder (“MM” in my example, see 1st screenshot) we come to different solution directories below:

For those solution directories (assume today you want to deploy Webpart1 but tomorrow Webpart2 and you all have them in one Git repository and all are handled by one configured Release pipeline) I created a Release variable localPath that can be set at releasetime.

Azure DevOps Release variables

This leds us to the point where we can relate to this in the npm install or our gulp tasks when it comes to a local file path:

npm install
gulp bundle task (gulp package-solution quite similar)

So depending on which webpart we want to deploy according to our variables above we would hand in different “packageFile” (we use it later!) and different “localPath” values and the task will find it’s package.json (for npm install) as well as it’s gulpfile.js

PowerShell Tasks and modern authentication

But now let’s come to the main point of this post. Let’s create the two PowerShell tasks to upload our app package and the assets to the library that represents our Office 365 public CDN. At first let me clarify which task to use as there are more outside (in the past for instance I used one from the marketplace). I now switched to the official Microsoft task.

Azure DevOps Task Template PowerShell (by Microsoft)

The first task is to upload the package to the app catalog. It is quite simple as beyond the script we do not really need to configure anything else. I skipped to give a working directory (I use cd in script instead) or provide environment variables here. Maybe worth to investigate in future.

Azure DevOps PowerShell task Deploy to App catalog

As the complete script did not fit into the screenshot here once again:

Write-Host ("Adding package " + $($env:packageFile) + " to the AppCatalog at https://" + $($env:tenant) + ".sharepoint.com/" + $($env:catalogsite))
cd $env:System_DefaultWorkingDirectory/MM/$env:localPath/sharepoint/solution/
Install-PackageProvider -Name NuGet -Force -Scope "CurrentUser" 
Install-Module SharePointPnPPowerShellOnline -Scope "CurrentUser" -Verbose -AllowClobber -Force
Import-Module SharePointPnPPowerShellOnline -Scope "Local" -WarningAction SilentlyContinue

Write-Host ("Connecting to Tenant " + $($env:tenant) + ".onmicrosoft.com with AppID " + $($env:SPOAppID))

Connect-PnPOnline –Url https://$(tenant).sharepoint.com/$(catalogsite) -Tenant "$(tenant).onmicrosoft.com" -ClientId $(SPOAppID) -PEMCertificate "$(PEMCertificate)" -PEMPrivateKey "$(PEMPrivateKey)"

Write-Output 'Connected to SPO'

Add-PnPApp -Path $env:packageFile -Publish -Overwrite
Write-Host Finished upload app package $($env:packageFile)

For debug reasons I left a couple of Write-Host but they are not necessary of course. Anyway the first shows quite well how to reference our release variables from above ($env:<ReleaseVariableName>).

After the first output we switch our current directory into our current solution and the folder where the .sppkg file resides.

Afterwards we install our PnP-PowerShell module with 3 lines of code.

But then it comes to the ‘magic’ point of this post, the modern authentication with PnP Online:

Connect-PnPOnline 
    –Url https://$(tenant).sharepoint.com/$(catalogsite) 
    -Tenant "$(tenant).onmicrosoft.com" 
    -ClientId $(SPOAppID) 
    -PEMCertificate "$(PEMCertificate)" 
    -PEMPrivateKey "$(PEMPrivateKey)"

We build our Url from known and obvious parts combined with our release variables, the Tenant as well.

We then hand in the ID of our App Registration and finally
our PEMCertificate and PEMPrivateKey string retrieved from our variable.

Finally I simplified the things again and added a simple Add-PnPApp cmdlet assuming SkipFeatureDeployment is always false. Giuliano de Luca shows a cool optional handling for this in his code repository.

The next task is quite the same:


Azure DevOps PowerShell task Upload to Office 365 public CDN
Write-Host ("Adding package " + $($env:packageFile)+ " to the AppCatalog at https://"+ $($env:tenant) + ".sharepoint.com/" + $($env:catalogsite))
cd $env:System_DefaultWorkingDirectory/MM/$env:localPath/

$cdnConfig = Get-Content -Raw -Path ("config\copy-assets.json") | ConvertFrom-Json
$bundlePath = $cdnConfig.deployCdnPath
$files = Get-ChildItem $bundlePath\*.*

Write-Output "Connecting to CDN-Site $env:CDNSite"

Connect-PnPOnline –Url $env:CDNSite -Tenant "$(tenant).onmicrosoft.com" -ClientId $(SPOAppID) -PEMCertificate "$(PEMCertificate)" -PEMPrivateKey "$(PEMPrivateKey)"

foreach ($file in $files) {
    $fullPath = $file.DirectoryName + "\" + $file.Name
    Write-Output "Uploading file $fullPath to folder $env:CDNLib"
    $f = Add-PnPFile -Path $fullPath -Folder $env:CDNLib
}

We do not need to install PnP Powershell anymore but now only cd to a different directory. Then we grab a JSon file from our repository to get a value from there. An elegant way to omit some release variables.

We once again authenticate with our certificate values to SharePoint.

Finally we use the (retrieved from Json config file) path value where our bundles reside to grab all files from there. We then iterate them one by one and upload them to the library/folder inside our CDN site.

Markus is a SharePoint architect and technical consultant with focus on latest technology stack in Office 365 and SharePoint Online development. He loves the new SharePoint Framework as well as some backend stuff around Azure Automation or Azure Functions and also has a passion for Microsoft Graph.
He works for Avanade and is based in Munich.
Although if partially inspired by his daily work opinions are always personal.
Secure Azure Functions Part 2 – Handle certificates with Azure KeyVault when accessing SharePoint Online

Secure Azure Functions Part 2 – Handle certificates with Azure KeyVault when accessing SharePoint Online

This is the second post of my little series on secure Azure Functions working with Office 365. The first one was about “simple” credential (user/password or ID/secret) access. Now we need to use an additional certificate.

Recently I spent lots of time with modern SharePoint authentication used in either Azure Automation or Azure Functions. For most of the parts there is some documenation but not as a whole and step-by-step guide. This is what this blog post wants to accomplish. One of the best existing posts is this one from Jeremy Hancock.

The Architecture Scenario

As in part 1 we use an Azure Function to be securely called from a SPFx webpart with AADHttpClient for instance. We do not use the user authentication but an impersonation. That is, an own Azure AD App Registration with own permissions. This can be a necessary scenario when you need elevated privileges (as SPFx directly only can use user permissions when calling SharePoint).

Example scenarios can be around provisioning or post-provisioning site modifications (where you want to allow specific users to handle stuff that needs elevated privileges).

01securelyaccessspofromazurefunction

The Azure Function is once again MSI enabled so it can authenticate “itself” against the Key Vault (which gave access to the function, see part 1). With the Client ID of an registered app, which is given SharePoint Api permissions, the Azure Function will access SharePoint.

Create a self-signed certificate

For this step we can reuse the certificate / description from my last blogpost.

But in short again:

  • Create a self signed certificate with New-PnPAzureCertificate cmdlet
  • Keep the PS window open, we need the certificate’s KeyCredentials in a minute
$Password = "******"
$secPassword = ConvertTo-SecureString -String $Password -AsPlainText -Force
$cert = New-PnPAzureCertificate -Out "AzureAutomationSPOAccess.pfx" - `
 -ValidYears 10 `
 -CertificatePassword $secPassword
 -CommonName "AzureAutomationSPOAccess" `
 -Country "DE" `
 -State "Bavaria"

$cert.KeyCredentials
{
    "customKeyIdentifier": "zUFQhchR6FJ0...",
    "keyId": "4d2fe8fc-0dbb-45a7-...",
    "type": "AsymmetricX509Cert",
    "usage": "Verify",
    "value":  "MIIDJDCCAgygAwIBAgIQV9qo..."
}

App registration and SharePoint Online Api

For this step we can reuse the certificate / description from my last blogpost.

In short again:

  • Go to your Azure Portal 
  • Switch to Azure Active Directory
  • Choose “App registrations (preview)” version (the standard works either, but…)
  • Register an App with a name of your choice
  • Provide adequate SharePoint Api permissions (Application permissions for an elevated scenario!)
  • Grant your permissions with an admin account 
  • Insert Key Credentials in app registration`s manifest settings
Register Azure AD App registration
Provide SharePoint Api permissions
Paste KeyCredentials from certificate to app registation manifest

Import certificate in Azure Key vault

This is also quite the same than loading the certificate to an Azure Automation account:

You have to import the .pfx file under “Certificates” to your Azure Key vault by entering a name and the given password (to make sure you are the one who “controls” the certificate)

Example Code

We need three parts for this:

  • Our key vault controller as we had it in part 1 as well
  • An authentication helper class for establishing our authentication / client context
  • The Azure Function itself using both parts mentioned beforehand

Retrieve certificate from Key vault

It might not seem obvious but this step is quite similar to that one in part 1. Although we imported a certificate above (and not a secret), we now need to retrieve the secret of exactly that certificate first. And this works quite the same than in part 1.

The ‘magic’ happens afterwards: While in part one we simply returned the retrieved secret value, we NOW use that value to create a X509Certificate2 from it and return that one for further usage.

Access SharePoint Online

To access SharePoint Online we use a simple CSOM / MSAL combination.

In our helper class this time (in part 1 of this series I retrieved it via the Azure Key vault but for an ID this is not 100% necessary) we retrieve our client ID from configuration manager (your local.settings.json for local debugging, respectively the “Application settings” of your Azure function).

Then we create our MSAL Authentication context quite similar to my last blog post. Next step is once again retrieving an access token but this time we provide a combination of our ID and a X509Certificate2.

Final thing is to create a CSOM client context and attach the access token to every request.

Using it in an Azure Function

To use that stuff is also no rocket science anymore. For simplicity reasons I minimized the SharePoint operation itself to a simple web.Title retrieval. Of course that part is much more code in other scenarios but here I wanted to put attention on Key vault access and SharePoint authentication only.

Only two lines are really important to mention here. At first we retrieve our certificate by using our KeyVaultAccess-controller from above in line 8. Next we retrieve our SharePoint ClientContext from our SPOAuthHelper in line 10.

Conclusion

Modern SharePoint authentication becomes more and more relevant. Furthermore there is a necessity for a secure but comfortable handling of secret artefacts such as credentials, app secrets or private keys. The combination of Azure Function, Azure Key vault and modern SharePoint authentication addresses this. 

 

Markus is a SharePoint architect and technical consultant with focus on latest technology stack in Office 365 and SharePoint Online development. He loves the new SharePoint Framework as well as some backend stuff around Azure Automation or Azure Functions and also has a passion for Microsoft Graph.
He works for Avanade and is based in Munich.
Although if partially inspired by his daily work opinions are always personal.

Executing batch requests with Microsoft Graph and SharePoint Framework (SPFx)

In my recent blogpost I wrote about using batch requests with the SharePoint Rest Api within a SharePoint Framework (SPFx) solution. Today I want to construct a similar scenario which shows batch requesting using the new Microsoft Graph access class within SPFx.

Please note that this approach  is currently, when writing this post (Jul-2018), in final preview mode and therefore not supported in production scenarios as it might be subject to change. A GA is expected with the next SPFx version (1.6.0) end of this month.

Update: This is now targeting the GA version from SPFx 1.6.0 on.

Lets start with a simple scenario. Suppose we have a bunch of Group IDs

Within our component we will do several things now. First within the constructor (you might use a Graph call several times within your code, otherwise you can also do it in your function) we instantiate a MSGraphClient.

As this is an async call now, it is debatable to do this in the constructor or at a later stage in componentDidMount. In larger projects I usually exclude the whole data stuff to a separate controller class which I instantiate in the constructor.
In a getGroupsData function we then create our requests based on the IDs of our Groups from above (Please note that we also handover an index which we can later use to simply identify the repsonse if needed as the repsonses might be ordered differently than the requests originally were):
What happens afterwards is one simple call to the Graph Api handing over all requests in the body. If no error occurs and we recieve a Status of 200 per response (also one single request might fail, for instance when we have provided a wrong Id) we can push the response part to our array based on our custom UnifiedGroup interface.
When every response is handled, we set our state which lets our component re-render as usual.
Please pay attention that there is a hard limit of 20 (!!) requests per batch request. So in case you would have more than 20 Ids (or something similar, this is a constructed scenarion of course) you need to create several batch requests, similar to a paging approach.
Before we can test our stuff, we also need to request permissions in the package-solution.json
For debugging with the workbench this is sufficient (this now works with SPFx 1.5.0!), when deploying our solution we have to grant that permissions by an admin tenant-wide also as described here.
Update: 2 additional things to mention here are the general request for “Windows Azure Active Directory” | “User.Read” which is required to have for all requests. On top I recently came across an obviously general limitation of having the string values for resources and scopes not more than 255 characters in total. So pay attention on this as well when having to request a significant number of Graph resources for instance. But as you only have to approve once you might split up your request over several packages but must rely on their all existence inside a tenant then.
Once we run our simple solution it might (simply rendered) look like this:
result
Finally for your reference the whole component’s source:

Use SharePoint Rest API Batch component to retrieve site logos

In the modern design of Office 365 and SharePoint Online in detail it is all about logos, photos and tiles or cards. Unfortunately there is still no easy Api to retrieve.

There is an undocumented version that helps maybe but only in case of ‘followed’ or ‘recent’ sites are what you want. Here is the issue and here the uservoice request.

In this post I want to show you another approach that uses the batch capability which is available for the SharePoint Rest API and can be easily used from the SPHttpClient class within SharePoint Framework (SPFx).

Furthermore the example is kept quite simple so you can also get an idea about batch requests with SharePoint Rest Api ans SPFx in general and adapt it to your own case.

Assume we have a bunch of site Urls in our use case:

When we start a batch we first need a url:

Now we have the problem that we cannot simply request the site properties as this would lead to totally different Urls which doesn’t work.

So in detail, a batch request with requests to
https://<yourtenant&gt;.shrepoint.com/sites/SiteA
https://<yourtenant&gt;.shrepoint.com/sites/SiteB
https://<yourtenant&gt;.shrepoint.com/sites/SiteC
won’t work but several request to the same site but different lists, items, e.g. will work.

Fortunately search helps out here. We can simply request the needed properties with a search query for a site with our specific URL from current context:

Now we have constructed and collected all of our requests. We can now send them to the server and handle the responses:

Two important things to explicitly mention here:
First we use Promise.All() to wait for all requests to be completed. If we would handle each one be one we would need to write to our state each time a request is done. Or we would store it in a variable but then the challenge is when are all done and we can transfer to state? A counter can help (increase on request, decrease on response) but Promise.All() is much simpler.
Second we have to handle another async call, the json() method. Therefore we build another array of requests and with another Promise.All() we handle our final JSon response.

As we have to handle the Response of a search call, we use the helper Interfaces as below:

This approach is taken from Elio Struyf’s SPFx search example webpart.

Finally we can render our data.

RestBatch_Result

As you can see I only used Groups respectively modern teamsites in my example. I like that they expose a site logo by default as a combination of an acronym and a randomly picked color. Modern communication sites display the same by default but do not expose the values (except in the above mentioned undocumented Api on followed or recent sites) or a built image as modern teamsites do. Mikael Svenson also commented on this a while ago, so we hope that Microsoft will improve the logo handling quite soon.
But I hope I gave you some ideas how to improve this yourself and also how to handle batch requests in general.

Now stay tuned for my next example where I will cover batch requests with Microsoft Graph and SharePoint Framework (SPFx).

Last not least the whole component class for your reference:

Extend PnP SharePoint Framework React ListView Control with a context menu

Extend PnP SharePoint Framework React ListView Control with a context menu

The ListView component from the PnP SharePoint Framework React Controls is really simple in use. And it’s furthermore easily extensible. In this little post I want to simply show how you can add a context menu to the list item like it’s available in the default modern experience of lists and like the “edit control block” in the classic experience.

Assume we have a simple list view webpart like the following

01_EmployeeListView_rel1

achieved by the following code

We now need to create another component which represents our context menu. Therefore we will use a combination of an IconButton and a ContextualMenu from the Office UI Fabric components.

The code for this additional component looks like this:

One of the tricks is here to give an empty iconName for the menuIconProps. This is because once you attach a menuProps Attribute to any Kind of Office UI fabric button a ChevronDown selector on the right side of the button will occur by default. With the menuIconProps Attribute you can adjust this, that is when specifying an empty Name you can remove it. This is what we want because we only want to have our “MoreVertical” icon which are the three dots in a vertical order.
To place this a bit more centric, we have small CSS manipulation as well:

Finally we need to put the pieces together. Therefore we will insert another Viewfield in the webpart code at the position of our choice, for instance after the “Lastname”:

{
        name: "",
        sorting: false,
        maxWidth: 40,
        render: (rowitem: IListitem) => {
	 const element:React.ReactElement<IECBProps> =React.createElement(
            ECB, {
	      item:rowitem
            }
          );
          return element;
        }      
},

We use the render method of IViewField. Inside we create our ECB component and as a property we handover the rowitem which is clicked. We could also handover functions that shall be executed inside the context menu component but be able to be bound to the parent component, that is the webpart which contains the ListView.

The result will look like the following:

02_EmployeeListView_ecb

And in action it shows which function and item was clicked:03_EmployeeListView_ecb_clicked