Wednesday, 15 January 2020

Create Microsoft Teams manifest manually for Personal app powered by SPFx

SPFx 1.10 was released recently which now includes support for Teams personal apps. Catch the announcement here: https://developer.microsoft.com/en-us/sharepoint/blogs/announcing-sharepoint-framework-1-10-extending-sharepoint-framework-across-microsoft-365/

To deploy a personal app with an SPFx package, you have the option of deploying the package to the SharePoint tenant app catalog and clicking on the "Sync to Teams" button which then makes the app available in Teams as shown here: https://docs.microsoft.com/en-us/sharepoint/dev/spfx/integrate-with-teams-introduction

But what if you are coming at it from the Teams app point of view? You already have a Teams app with a bot or a messaging extension and want to add the SPFx powered personal app to it. You probably don't want to use the "Sync to Teams" option in this case because then your SPFx web-part will be available as a separate app in the Teams app catalog.

Fortunately, it's very simple to define a staticTab in the Teams manifest which points to the SPFx webpart. This then makes the SPFx webpart available as a teams personal app:

Notice the teams and personal query string parameters as they are very important. You will also have to replace the component id with the id of your web-part.

I have also updated the official MS Docs with this approach:
https://docs.microsoft.com/en-us/sharepoint/dev/spfx/web-parts/guidance/creating-team-manifest-manually-for-webpart

Thanks to my colleague Jarbas for working with me in figuring out this one!

Monday, 2 December 2019

SharePoint Framework Web Part and Property Pane Lifecycles

I was working on a SharePoint Framework webpart, especially on the property pane, and needed to understand when the SPFx WebPart lifecycle methods are executed. Specifically, the order in which they are fired.

I tried searching for this but couldn't find much information, so thought of creating this post as it might be helpful for other who might be looking for it.

The Microsoft docs on these methods/APIs are fairly extensive and they give a good overview of what each method does:
https://docs.microsoft.com/en-us/javascript/api/sp-webpart-base/baseclientsidewebpart?view=sp-typescript-latest#methods
https://docs.microsoft.com/en-us/javascript/api/sp-webpart-base/basewebpart?view=sp-typescript-latest

What is missing though is the order in which these methods are fired. So this post should serve as a nice complement to the docs.

I should mention that this post only focuses on the native SPFx lifecycle methods. If you are creating an SPFx webpart with React for example, the react lifecycle is out of scope for this post as there is loads of information available already on the interwebs.


SPFx webpart method execution order:


When loading the web part on a page, the methods are fired in the following order:


1) protected onAfterDeserialize(deserializedObject: any, dataVersion: Version): TProperties;

2) protected onInit(): Promise<void>;

3) protected render(): void;

4) protected onBeforeSerialize(): void;

When the web part is removed from a page, the methods are fired in the following order:


1) protected onDispose(): void;


SPFx webpart property pane method execution order:


Opening the property pane:

1) protected loadPropertyPaneResources(): Promise<void>

2) protected getPropertyPaneConfiguration(): IPropertyPaneConfiguration;

3) protected onPropertyPaneRendered(): void;

4) protected onPropertyPaneConfigurationStart(): void;


Updating the properties in the property pane:


The SPFx property pane can be set in either the reactive mode or in a non-reactive mode:

"Reactive implies that changes made in the PropertyPane are transmitted to the web part instantly and the user can see instant updates. This helps the page creator get instant feedback and decide if they should keep the new configuration changes or not.

NonReactive implies that the configuration changes are transmitted to the web part only after "Apply" PropertyPane button is clicked."

When in reactive mode, if any property is changed, the methods are fired in the following order:


1) protected onPropertyPaneFieldChanged(propertyPath: string, oldValue: any, newValue: any): void;

2) protected render(): void;

3) protected getPropertyPaneConfiguration(): IPropertyPaneConfiguration;

4) protected onPropertyPaneRendered(): void;

5) protected onPropertyPaneConfigurationComplete(): void;



When in non-reactive mode, if any property is changed, the methods are fired in the following order:


1) protected onPropertyPaneFieldChanged(propertyPath: string, oldValue: any, newValue: any): void;

2) protected getPropertyPaneConfiguration(): IPropertyPaneConfiguration;

3) protected onPropertyPaneRendered(): void;


When in non-reactive mode, after clicking on the "Apply" button, the methods are fired in the following order:

1) protected onAfterPropertyPaneChangesApplied(): void;

2) protected render(): void;

3) protected onPropertyPaneConfigurationComplete(): void;

4) protected onPropertyPaneRendered(): void;


When the property pane is closed by clicking on the "X" button

1) protected onPropertyPaneConfigurationComplete(): void;


Hope you found the post helpful! Let me know if I might have missed any. Would love to update this post in the future.

Thursday, 7 November 2019

Building a Microsoft Teams Bot: Get Team context details including Office 365 Group and SharePoint site url

The Microsoft Bot Framework v4.6 was released this week at Ignite and it's got some really great additions:
https://github.com/microsoft/botframework/blob/master/whats-new.md#november-2019-ignite

One thing which I am very happy about is that building Bots for Microsoft Teams has become way easier now!

This wasn't always the case. Previously, the Bot Framework was separate to the Teams Bot Builder and they both didn't play nice all the time. Throw in more stuff like Bot Framework v3/v4, Messaging extensions, Adaptive Cards and it lead to tweets like this:


But now, the Teams Bot Builder is part of the the Bot Framework SDK itself which is very good news. If you are just getting started building Bots for Microsoft Teams, you only need to install the Bot Framework package. Apart from that, the code to work with Microsoft Teams has been simplified as well.

Imagine you are building a Teams Bot and it needs to interact with the Office 365 Group which underpins the Team. Or maybe the Bot needs to store or retrieve some data from the SharePoint site associated with the Team. Let's see how easy it is now to achieve this:

Before we look at the code, make sure you are using the Microsoft.Bot.Builder 4.6+ version of packages in your Bot:

https://github.com/Microsoft/botbuilder-dotnet/#packages
https://www.nuget.org/packages/Microsoft.Bot.Builder/

We will also need the Microsoft Graph .NET SDK:
https://docs.microsoft.com/en-us/graph/sdks/sdk-installation

And here is the code:


We are using the new TeamsInfo class available in the Bot Framework to get the current team details. This class also has a few other helper methods which you might find useful:
https://github.com/microsoft/botbuilder-dotnet/blob/master/libraries/Microsoft.Bot.Builder/Teams/TeamsInfo.cs

Internally the TeamsInfo.GetTeamDetailsAsync method calls the `/v3/teams/{team-id}` API endpoint to get the Office 365 Group id (a.k.a AADGroupId in the API). We can then use the Microsoft Graph API to get the other details including the SharePoint site url.

Hope this helps! For more details on building bots for Microsoft Teams, have a look at the official docs: https://docs.microsoft.com/en-us/microsoftteams/platform/bots/how-to/create-a-bot-for-teams

Wednesday, 30 October 2019

Getting anonymous thumbnails of SharePoint Online files with Microsoft Graph

If you are developing an application based on the Microsoft 365 platform which also uses files stored in SharePoint Online, chances are that you might want to make the file thumbnails available on a device (or client) without going through SharePoint authentication. It could be a mobile app or Microsoft Teams app which needs to show the thumbnails. In these cases, the end user has already signed into the app so might not be a good idea to ask them to sign in again to access files stored in SharePoint.

One thing which comes to mind straight away is to use the Data URLs of the thumbnail images. But data URLs can get fairly big as they are just the base 64 representation of the images. Also, if you have large images and you need to display a lot of them at the same time, the data travelling over the wire to your device can get fairly big.

Fortunately, the Microsoft Graph provides a great way to get the thumbnail of a file. It is also provided as an anonymously accessible link (which expires in 1 hour) so we don't have to worry about the user having to sign in again to SharePoint. More details on Microsoft docs:
https://docs.microsoft.com/en-us/graph/api/driveitem-list-thumbnails?view=graph-rest-1.0&tabs=http

This approach works for getting the thumbnails of any type of file stored in SharePoint Online. But in this post, I am going to focus only on modern pages.

First, let's see how the code for this looks in the Microsoft Graph .NET SDK:

This code translates to the following Graph REST API call:

and the response:
(click to zoom)

The thumbnail url returned here can be used on any device, app or Adaptive Card to display the image without the need for authenticating to SharePoint. But bear in mind that this image url is only valid for 1 hour as there is an Azure AD access token attached to it. After that you might have to request a new url by making the same Microsoft Graph call.

Hope this helps!

Friday, 4 October 2019

Microsoft Teams messaging extensions: User authentication, OAuth and Microsoft Graph

Microsoft Teams messaging extensions allow us to enhance teams messages with business data. We are able to fetch information (e.g. from Microsoft Graph or 3rd party APIs) based on various factors like the current user, current team or current channel and post it as part of a message using rich Adaptive cards.


This gives us a great way of creating Teams based integrations with other Line of Business (LOB) applications.

I won't go much deeper into the different possibilities with messaging extensions in this post. Instead, we will focus more on how they are built and how to authenticate the current user.

To know more about messaging extensions, have a look at the Microsoft docs:
https://docs.microsoft.com/en-us/microsoftteams/platform/concepts/messaging-extensions/messaging-extensions-overview

Teams messaging extension architecture:


The way in which the messaging extensions work is by leveraging the Microsoft Bot Framework and utilising the following moving pieces:

1) A Bot Channel Registration which is essentially the identity of the Bot/Messaging extension. We need this to get the Bot Id and also to set "Microsoft Teams" as one of the channels served by the bot.

2) An endpoint which will receive (and respond to) HTTP POST messages from teams when the messaging extension commands are invoked.

3) A Teams App Manifest which contains the JSON specifying the messaging extension properties, the Bot  Id, and the messaging endpoint.

Those are the primary building blocks of a Teams messaging extension (or even a Teams Chat Bot for that matter, but that's out of scope for this post)

To see a walk-through of building a messaging extension from scratch, check out Cameron Dwyer's post: https://camerondwyer.com/2019/09/09/how-to-create-a-microsoft-teams-messaging-extension-pop-up-dialog-with-a-custom-ui/

Fetching data from Microsoft Graph as the current user (delegated authentication)


This is how the sign in flow will look. The user will have to sign in only once into the app. After that, the token flow (including the access tokens and refresh tokens) will be handled by the Bot Framework.

The user is prompted to sign in the first time they launch the compose messaging extension. After the sign in is completed, the messaging extension is able to show "security trimmed" data from the Graph. In this case, it's the groups the current user has joined:


Now let's see how we can leverage the Microsoft Graph in our messaging extensions. Before fetching data from the Graph, we will need an Azure AD OAuth token for the current user in Teams. To get the token flow working, first we need to create and Azure AD App Registration and give it necessary permissions:


Next, we need to create and configure the Bot Channel Registration:


Next, create and configure an OAuth Connection Setting in the Bot Channel Registration. The Client Id, Client Secret and Tenant Id should come from the AAD App Registration created in the previous step.



And here is the code to include in the Bot which handles the AAD sign in flow of the user. I am using the Bot Framework v4 for this Bot:


This code will fetch you the access token needed for calling the Graph. After that you can use the Graph SDK to get the required data:


Hope this was helpful. Given the complexity of Microsoft Teams development at this time, this post wasn't as comprehensive as I wanted it to be. There are challenges to getting everything to work together including Bot Framework v4, Teams Bot Builder (preview), Adaptive Cards and Messaging extensions. Hope the story becomes much simpler in the future.

Monday, 2 September 2019

Create SPFx Library components containing Office UI Fabric React

When using Office UI Fabric React (OUIFR) components in SPFx projects, if you analyse the bundle structure you will notice that OUIFR components take up a lot of space which leads to increased bundle size.

If there are multiple SPFx components loaded on the page which depend on OUIFR components, the size of each bundle will be affected, as by default the OUIFR components are included in each SPFx bundle.

One way to mitigate this issue is to include all your custom components (which depend on OUIFR) into an SPFx library component and then consume the library component from SPFx webparts and extensions. This will make sure that if you have reusable custom components, they won't be loaded multiple times on the page if multiple SPFx webparts (or extensions) are consuming them.

Let's see how to achieve this. We will be working with SPFx 1.9.1 which contains the GA version of Library Components:

1) Create SPFx Library and Consumer component structure


First, make sure you have an SPFx library project as well as a "consumer" SPFx project containing webparts (or extensions). Instructions on how to create this are in the Microsoft docs: https://docs.microsoft.com/en-us/sharepoint/dev/spfx/library-component-tutorial

The code for this post is also available on GitHub if you want to have a look: https://github.com/vman/spfx-lib-components-ouifr


2) Create a new custom react component which internally uses Office UI Fabric React


In the library component project, create a new react component in a new file e.g. ButtonComponent.tsx


Here are the contents of the custom react component:


3) Update the index.ts file


In the index.ts file of the library component, include the new component to be exported:


4) Update config.json


Next, in the config/config.json file of the library component, make sure that the entry point is pointing to /lib/index.js


This step was not necessary in SPFx 1.8.2-plusbeta but seems there is a bug in SPFx 1.9.1. I have created a GitHub issue here:

5) Update the consumer web part


Make sure that the library component is referenced in the consumer webpart e.g. through npm link or by using a monorepo manager like rush or lerna.

More details on using npm link in this in the Microsoft docs: https://docs.microsoft.com/en-us/sharepoint/dev/spfx/library-component-tutorial

And finally, in your consumer SPFx react webpart, you can reference the custom component:


When you deploy both the SPFx packages in the app catalog and then add them on a page, you will see different bits of code being loaded separately:



And that's it! Sample repo on GitHub: https://github.com/vman/spfx-lib-components-ouifr

Monday, 1 July 2019

Deploying Azure Function Proxies along with Function Apps

I am working with Azure Function Proxies in my latest project and I have found them to be a really handy tool! With Function Proxies, we can expose endpoints in a Functions App which redirect to other resources in Azure (or anywhere really).

I won't go into much detail describing Proxies, Microsoft docs has some great info already:

"With proxies, you can specify endpoints on your function app that are implemented by another resource. You can use these proxies to break a large API into multiple function apps (as in a microservice architecture), while still presenting a single API surface for clients."
https://docs.microsoft.com/en-us/azure/azure-functions/functions-proxies

In my case, we are working on a front-end app built using TypeScript and React which uses Azure Functions as the back-end. For hosting the front-end, we have turned on the static website hosting for blob storage and then placed the HTML, JS and CSS files in it. Then, used Azure Function Proxies to redirect the endpoints in the Function App to the blob storage URLs of the front-end resources. It's all working quite nicely!

Only speed-bump in this type of architecture is the cold start experienced by serverless resources on the consumption plan. This is not a problem for us right now because this application is a proof of concept for a larger project. (There are other options available as well which include moving the Function App to an App Service Plan or using the Azure Functions Premium plan when it comes out preview. But that is a discussion for another time)

Back to the current post! When I was looking into deploying this application as part of the CI/CD pipeline using Azure DevOps, I was looking for an easy way to deploy the Azure Function Proxy configuration as well. Fortunately, I came across this Microsoft docs article which talks about a file called proxies.json. If this file is found within your Function App, the functions runtime reads it and creates the necessary proxies!

Here is how my proxies.json file looks in Visual Studio. Make sure the file is copied to the output directory:


And once the Functions App is deployed:


This way, if you are deploying and recreating Function Apps with your CI/CD pipeline, you can automate the creation of Function Proxies as well!

Hope you found this post useful.