Wednesday 26 April 2017

Calling an Azure Function from a SharePoint Framework web part (SPFx) – part 1: use of PnP Core, CORS and continuous deployment

Azure Functions are the cool thing these days, mainly because they’re just so damn useful. They can work out cheaper than other hosted code (e.g. WebJobs), but they’re also very flexible. You can define a function which runs on a timer or when an item is added to a queue (just like a WebJob), or you can define one to execute when when a HTTP endpoint is hit. In that respect it’s similar to a web API, but simpler and with less of the infrastructure. If I have a button in a page or web part that needs to do something that’s simpler on the server-side (use a method in the OfficeDev PnP library perhaps), I really like the idea of hooking the button up to an Azure Function. My click handler would then POST to the Function’s endpoint, the server-side code will execute, and then the client-side code will receive the response.

I thought it would be good to show this in a SPFx web part – and to show how data is passed between client and server. We’ll use the example of having our Azure function make use of the OfficeDev PnP core library. Specifically, my web part provisions a modern page into a site and adds an SPFx web part – both things that are harder to do purely on the client side. I’m splitting this into two articles, but overall I’m trying to show a few things here:

Part 1 – setup, use of PnP Core, CORS and continuous deployment (this article):
  • Initial creation of Function
  • Deployment of function code (using Continuous Deployment from GitHub)
  • Allowing CORS on an Azure Function so that it can be called from JavaScript (including a special entry for the SPFx workbench)
  • Use of SharePoint PnP Core library - via Azure Functions NuGet support
  • Use of App Settings (environment variables) in an Azure Function
Part 2 – calling from SPFx and passing data (next article):
  • Code for the Azure Function side (i.e. the work to create a modern page from some passed parameters)
  • Code for the SPFx side
  • Passing data to the function and adding correct headers
  • Returning data from the function, and displaying success/failure in our SPFx web part

Overall we’ll have a solution which creates a modern SharePoint page from a button click – but the pattern can be used for whatever you want.

Azure Functions – different types, and use of .NET code

As a reminder, when you define a function you specify the trigger – these include:

  • HTTPTrigger (the one we’ll use here)
  • TimerTrigger – execute something on a scheduled basis, as you could do with a WebJob
  • QueueTrigger – execute when something is added to a queue
  • Lots of others – including BlobTrigger and “Generic webhooks” (N.B. not currently what you’d use for SharePoint webhooks)

Of course, use of a HTTPTrigger doesn’t need to be in response to a button click – it could be any time you can post something to the server-side. But a button-click is what we’ll use here. Picking up some awareness of pricing of Azure Functions is a good idea, in particular the difference between the Consumption plan and an App Service plan. In most cases the Consumption plan is what you’ll prefer (and your costs will be peanuts), except perhaps for production implementations that need to run at scale and/or when you have existing resources running on an App Service plan. Anyway, that’s a slightly different topic and you can read more at Choose the correct service plan for Azure Functions.

Developing Azure Functions code with .NET
 
UPDATE – these days you can use Visual Studio 2017 to create functions with full IntelliSense support and the ability to debug locally. I highly-recommend this approach if you’re writing in C#. You’ll need Azure Functions Tools for Visual Studio 2017, but this gives you .cs files and a typical VS experience, rather than .csx files (and less support).
 
The rest of this article does continue with the .csx approach, but the important things apply to either flavour (e.g. optionally syncing from Github, configuring CORS, using PnP code from NuGet etc.)
 
If you're new to Azure Functions, note that the development model for .NET is different in a couple of places:
  • There's no Visual Studio solution - it's just a collection of files in a directory
  • The main file is a csx file, and you won't get IntelliSense support here
  • You can deploy other assemblies and make use of NuGet packages, but this is done in a different way
Overall, I find a nice approach for developing more complex things is to use Visual Studio to create a DLL/library project for most of my logic, with an accompanying console app to help with local testing. The DLL gets deployed to the BIN directory of the Azure Function, and you can call into it from the function code (CSX file). That’s not the only way, but I like it. However, in the example shown here we’ll keep things simple by having our implementation in the .csx file.

Let’s get started on creating our function.

Create the Azure Function app

  1. Open the Azure portal, and find the option to create a new Function App.
  2. Specify the app name and any existing Resource Group and Storage Account that you may have (if not, you’ll need to create these prerequisite containers):

    SNAGHTMLf8d5e49
  3. Once the app has finished creating, find it in the portal (e.g. by accessing the “recent” section) and click into it.
  4. Click the “New Function” button: 

    SNAGHTMLc1a9b2
  5. I then prefer to use the “custom function” path:

    SNAGHTMLc42e0b
  6. Find the “HttpTrigger-CSharp” template (you might want to filter down to C# templates only using the dropdown):

    SNAGHTMLc603f4
  7. Give the function a name – we’ll also leave the “Authorization level” as the default of “Function”: 

    SNAGHTMLc6a17c
  8. Click Create – you should now see the integrated editor: 

    SNAGHTMLc79300
  9. You can now play around with running the function – consider how data is passed to the function and returned for example.

You’ll find that the integrated editor is great for some initial playing. But as you get more serious, I personally find it slicker to set-up some continuous deployment from source control, whether that’s GitHub or Visual Studio Online. Yes, you do have to commit/check-in each time you want to test your updated code – but that feels better than a) using the integrated editor and b) manually copying files using the Kudu interface. If source control integration feels a bit heavyweight for your needs, consider also the options of sync’ing from OneDrive or Dropbox – cool stuff I suppose, at least if you don’t really need true source control.

Deploying files to an Azure Function via GitHub integration (optional)

So this is an optional step, but since we’re here let’s go through the high level. The only complexity is doing things in the right order and making sure your folder is “at the right level” for how an Azure Function expects to have it’s files. The process isn’t hugely different for other systems such as Visual Studio Online by the way. The full documentation is at https://docs.microsoft.com/en-us/azure/azure-functions/functions-continuous-deployment, but here’s my summary with screenshots:

  1. First create yourself a repository:

    SNAGHTML128454d7
  2. Then clone it to the directory you want to work in on your machine:

    SNAGHTML554aec3

    SNAGHTML555fdb9
  3. Now open the directory in VS Code, and add the files for your function – you need to obtain these by copying from the Function you created earlier. It’s only a a couple of files, so I just copy the contents between the Azure portal and a file I created in VS Code. At this point it’s just the default content of these files – so I suggest making a simple code change to help us check later that the deployment is happening properly (e.g. make a simple change to one of the logging statements):

    SNAGHTML55e7b7e
  4. Once your files are ready, go back into the Azure portal and find the “Deployment options” link where continuous deployment is configured:

    SNAGHTML55fbe5e

  5. Click that link, then click the “Setup” button and choose GitHub:

    SNAGHTML56094e8
    SNAGHTML5615bd2
  6. Now walk through the process of pointing to your GitHub repository and providing authentication details:

    SNAGHTML56233f2
  7. Now we need to commit our files to GitHub – you can do this from the command-line if you like, or using VS Code like this:

    SNAGHTML5637423
    SNAGHTML5656a84
  8. Once the code is checked-in, examining the file in the Azure Functions portal should show your code change:

    SNAGHTMLba69a24

So, we’re now in good shape for developing our code. We’re no longer restricted to the web-based editor – instead, we can use whatever editor we like and properly store our Azure Function files in source control.

Enable CORS on the Azure Function

The next step is to ensure our Function can be called from JavaScript in a web page – and that means CORS support must be added. This is critical even to be able to test with the SPFx workbench, and we need to specify whatever URLs we will use (including the local workbench URL). To do this, find the “CORS” setting in the “Platform features” area of your Function:

SNAGHTML7350bc9

Once in there, specify any URL domain which will host JS code which will call into your Function – as in the image below, this is typically your Office 365 tenant domain(s) and also the local SPFx workbench URL (https://localhost:4321):

SNAGHTML73c8aab

Click “Save” to store the settings. Your Azure Function can now be called from SPFx.

Add the SharePoint PnP Core component via NuGet

To call into SharePoint PnP methods, the best option is to use Azure Functions support for NuGet – as an alternative you could obtain the PnP DLL and upload it to your function’s bin directory, but the NuGet way is more straightforward. The first time the code runs, any NuGet packages you specify as dependencies get downloaded and installed to your Function’s directory.

This is done by adding a project.json file in the directory of your Azure Function:

SNAGHTML7417101

Add content like this to specify the “SharePointPnPCoreOnline” NuGet package:

If you configured source control integration earlier, remember you’ll need to check-in now so that the code builds:

SNAGHTMLad0d181

Configure App Settings for SharePoint credentials

As the final preparation step, we’ll add some App Settings variables to store the username/password used to call into SharePoint (to create our modern page). We’re doing this because we’ll authenticate to SharePoint using SharePointOnlineCredentials (i.e. a simple username and password). For real-life uses you should consider using app authentication, be it of the SharePoint Add-in variety OR the Office 365/Azure AD app variety – in the latter case, you’d need to use adal.js or similar to obtain an access token to pass to your function of course (UPDATE – no longer. You can now use the AadHttpClient or MSGraphClient objects built into SPFx v 1.4.1 or later – these can be used to call a web API secured with AAD. See Consuming APIs secured with Azure AD within the SharePoint Framework). In this case, we’ll do two things to add some security and manageability to things:

  • Ensure our Azure Function requires simple auth in the form of an “API key” – the calling code must provide this
  • Store the credentials to call into SharePoint as App Settings of our Azure Function – that way they’re not hard-coded anywhere or stored in any particular file in clear text

Configuring App Settings for a Function is just like doing it for any Azure web app:

  1. Go to the “Application Settings” area within “Platform Features” in your Function app:

    SNAGHTMLaebf4f4
  2. Once there, enter a key/value for the username and password you wish to connect to SharePoint with:

    SNAGHTMLaed6414
  3. Click “Save”. These values will now be available to your code.

The corresponding C# code to use in your Function to fetch these values is this:

string ADMIN_USER_CONFIG_KEY = "SharePointAdminUser";
string ADMIN_PASSWORD_CONFIG_KEY = "SharePointAdminPassword";
string adminUserName = System.Environment.GetEnvironmentVariable(ADMIN_USER_CONFIG_KEY, EnvironmentVariableTarget.Process);
string adminPassword = System.Environment.GetEnvironmentVariable(ADMIN_PASSWORD_CONFIG_KEY, EnvironmentVariableTarget.Process);

 

Summary

We’re now complete with the setup steps. Our Azure Function is configured with CORS, is ready to call into the SharePoint PnP Core library, has some App Settings for credentials, and is configured with Continuous Deployment from GitHub. In the next post we discuss the code used on both sides – the TypeScript/SPFx code to call the function, and the code inside the function which does the work - see Part 2 - calling from SPFx and passing data.

1 comment:

Unknown said...

Great post! Looking forward to Part II!